diff --git a/.browserslistrc b/.browserslistrc index 04395b913c9c..968ff45a7552 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1,9 +1,14 @@ [production] -last 2 Firefox versions -last 2 Chrome versions -last 2 Safari versions -> 0.25% -not ie 11 +Firefox > 0 and last 2 years and > 0.01% +Chrome > 0 and last 2 years and > 0.01% +Safari > 0 and last 2 years and > 0.01% +Edge > 0 and last 1 years and > 0.01% +Opera > 0 and last 2 years and > 0.01% +> 0.2% +not op_mini all +not and_uc < 100 +not android < 100 +not dead [dev] last 1 chrome versions diff --git a/.eslintignore b/.eslintignore index c516d7511b78..6ea478bc2bf7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,7 @@ /.chromium /build /built_assets +/bwc_tmp /config/apm.dev.js /data /html_docs diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9346def6aafd..a90e3c4ac223 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @ananzh @kavilla @seanneumann @AMoo-Miki @ashwin-pc @joshuarrrr @abbyhu2000 @zengyan-amazon @kristenTian @zhongnansu @manasvinibs @ZilongX @Flyingliuhub +* @ananzh @kavilla @seanneumann @AMoo-Miki @ashwin-pc @joshuarrrr @abbyhu2000 @zengyan-amazon @kristenTian @zhongnansu @manasvinibs @ZilongX @Flyingliuhub @BSFishy diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 0ba694cbf213..c8dfef417daa 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -34,8 +34,10 @@ jobs: installation_id: 22958780 - name: Backport - uses: VachaShah/backport@v2.1.0 + uses: VachaShah/backport@v2.2.0 with: github_token: ${{ steps.github_app_token.outputs.token }} head_template: backport/backport-<%= number %>-to-<%= base %> files_to_skip: "CHANGELOG.md" + labels_template: "<%= JSON.stringify([...labels, 'autocut']) %>" + failure_labels: "failed backport" diff --git a/.github/workflows/build_and_test_workflow.yml b/.github/workflows/build_and_test_workflow.yml index 27fbbb2c4e63..82da6e3c092d 100644 --- a/.github/workflows/build_and_test_workflow.yml +++ b/.github/workflows/build_and_test_workflow.yml @@ -29,11 +29,12 @@ env: jobs: build-lint-test: - name: Build and Verify on ${{ matrix.name }} + name: Build and Verify on ${{ matrix.name }} (ciGroup${{ matrix.group }}) strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] + group: [1, 2, 3, 4] include: - os: ubuntu-latest name: Linux @@ -72,14 +73,9 @@ jobs: if: matrix.os != 'windows-latest' run: echo "YARN_CACHE_LOCATION=$(yarn cache dir)" >> $GITHUB_ENV - - name: Configure Yarn Cache (Windows) - if: matrix.os == 'windows-latest' - run: | - echo "YARN_CACHE_LOCATION=$(yarn cache dir)" >> $env:GITHUB_ENV - echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%" - - name: Initialize Yarn Cache uses: actions/cache@v3 + if: matrix.os != 'windows-latest' with: path: ${{ env.YARN_CACHE_LOCATION }} key: yarn-${{ hashFiles('**/yarn.lock') }} @@ -95,18 +91,24 @@ jobs: run: yarn osd bootstrap || yarn osd bootstrap - name: Run linter + # ciGroup 1 of unit-tests is shorter and Linux is faster + if: matrix.group == 1 && matrix.os == 'ubuntu-latest' id: linter run: yarn lint - name: Validate NOTICE file + # ciGroup 1 of unit-tests is shorter and Linux is faster + if: matrix.group == 1 && matrix.os == 'ubuntu-latest' id: notice-validate run: yarn notice:validate - - name: Run unit tests with coverage + - name: Run unit tests group ${{ matrix.group }} with coverage id: unit-tests - run: yarn test:jest:ci:coverage + run: yarn test:jest:ci:coverage --ci-group=${{ matrix.group }} - name: Run mocha tests with coverage + # ciGroup 1 of unit-tests is shorter + if: matrix.group == 1 id: mocha-tests run: yarn test:mocha:coverage @@ -115,9 +117,11 @@ jobs: uses: codecov/codecov-action@v3 with: directory: ./target/opensearch-dashboards-coverage - flags: ${{ matrix.name }} + flags: ${{ matrix.name }}_${{ matrix.group }} - name: Run integration tests + # ciGroup 1 of unit-tests is shorter + if: matrix.group == 1 id: integration-tests run: yarn test:jest_integration:ci @@ -168,14 +172,9 @@ jobs: if: matrix.os != 'windows-latest' run: echo "YARN_CACHE_LOCATION=$(yarn cache dir)" >> $GITHUB_ENV - - name: Configure Yarn Cache (Windows) - if: matrix.os == 'windows-latest' - run: | - echo "YARN_CACHE_LOCATION=$(yarn cache dir)" >> $env:GITHUB_ENV - echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%" - - name: Initialize Yarn Cache uses: actions/cache@v3 + if: matrix.os != 'windows-latest' with: path: ${{ env.YARN_CACHE_LOCATION }} key: yarn-${{ hashFiles('**/yarn.lock') }} @@ -265,14 +264,9 @@ jobs: if: matrix.os != 'windows-latest' run: echo "YARN_CACHE_LOCATION=$(yarn cache dir)" >> $GITHUB_ENV - - name: Configure Yarn Cache (Windows) - if: matrix.os == 'windows-latest' - run: | - echo "YARN_CACHE_LOCATION=$(yarn cache dir)" >> $env:GITHUB_ENV - echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%" - - name: Initialize Yarn Cache uses: actions/cache@v3 + if: matrix.os != 'windows-latest' with: path: ${{ env.YARN_CACHE_LOCATION }} key: yarn-${{ hashFiles('**/yarn.lock') }} @@ -324,7 +318,7 @@ jobs: working-directory: ./artifacts strategy: matrix: - version: [osd-2.0.0, osd-2.1.0, osd-2.2.0, osd-2.3.0, osd-2.4.0, osd-2.5.0] + version: [osd-2.0.0, osd-2.1.0, osd-2.2.0, osd-2.3.0, osd-2.4.0, osd-2.5.0, osd-2.6.0, osd-2.7.0] steps: - name: Checkout code uses: actions/checkout@v3 diff --git a/.i18nrc.json b/.i18nrc.json index 64ca6528aa5e..91d3b80b80a0 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -61,11 +61,17 @@ "visTypeXy": "src/plugins/vis_type_xy", "visualizations": "src/plugins/visualizations", "visualize": "src/plugins/visualize", - "apmOss": "src/plugins/apm_oss", "usageCollection": "src/plugins/usage_collection" }, "exclude": [ - "src/legacy/ui/ui_render/ui_render_mixin.js" + "src/legacy/ui/ui_render/ui_render_mixin.js", + "src/plugins/home/public/application/components/tutorial", + "src/plugins/home/server/tutorials", + "src/core/server/rendering/views/template.tsx", + "src/plugins/data/public/search/errors/timeout_error.tsx", + "src/plugins/home/public/application/components/welcome.tsx", + "src/plugins/vis_type_timeline/server/series_functions/graphite.js", + "src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js" ], "translations": [] } diff --git a/.lycheeexclude b/.lycheeexclude index 35ae861e8f91..a9d1f1018022 100644 --- a/.lycheeexclude +++ b/.lycheeexclude @@ -119,5 +119,7 @@ http://www.creedthoughts.gov https://media-for-the-masses.theacademyofperformingartsandscience.org/ https://yarnpkg.com/latest.msi https://forum.opensearch.org/ -https://facebook.github.io/jest/ -https://facebook.github.io/jest/docs/cli.html +https://facebook.github.io/jest/* +http://helpmenow.com/problem2 +https://sass-lang.com/* +http://api.jquery.com/* diff --git a/.stylelintrc.yml b/.stylelintrc.yml index 8a70ee1dd008..ad81fc065f7d 100644 --- a/.stylelintrc.yml +++ b/.stylelintrc.yml @@ -1,5 +1,6 @@ extends: - stylelint-config-standard-scss + - '@osd/stylelint-config' rules: # while we still use node-sass, only legacy rgb() notation is allowed color-function-notation: "legacy" diff --git a/CHANGELOG.md b/CHANGELOG.md index ecded257ee29..8cfc02244835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,18 +13,24 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [CVE-2022-37599] Bump loader-utils from `2.0.3` to `2.0.4` ([#3031](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3031)). Backwards-compatible fixes included in v2.6.0 and v1.3.7 releases. - [CVE-2022-37603] Bump loader-utils from `2.0.3` to `2.0.4` ([#3031](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3031)). Backwards-compatible fixes included in v2.6.0 and v1.3.7 releases. - [WS-2021-0638] Bump mocha from `7.2.0` to `10.1.0` ([#2711](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2711)) -- Bump `joi` to v14 to avoid the possibility of prototype poisoning in a nested dependency ([#3952](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3952)) +- [CVE-2023-26115] Bump `word-wrap` from `1.2.3` to `1.2.4` ([#4589](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4589)) +- Bump `node-sass` to a version that uses a newer `libsass` ([#4649](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4649)) ### 📈 Features/Enhancements -- [Multiple DataSource] Add support for SigV4 authentication ([#3058](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3058)). Backwards-compatible feature included in v2.6.0 release. -- Add plugin manifest config to define OpenSearch plugin dependency and verify if it is installed on the cluster ([#3116](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3116)) -- Replace re2 with RegExp in timeline and add unit tests ([#3908](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3908)) +- Enable theme-switching via Advanced Settings to preview the Next theme ([#4475](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4475)) +- Optimize `augment-vis` saved obj searching by adding arg to saved obj client ([#4595](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4595)) +- Add resource ID filtering in fetch `augment-vis` obj queries ([#4608](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4608)) +- Reduce the amount of comments in compiled CSS ([#4648](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4648)) +- [Discover] Update styles to compatible with OUI `next` theme ([#4644](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4644)) ### 🐛 Bug Fixes - [Chore] Update deprecated url methods (url.parse(), url.format()) ([#2910](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2910)) - Cleanup unused url ([#3847](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3847)) +- Fix Node.js download link ([#4556](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4556)) +- [TSVB, Dashboards] Fix inconsistent dark mode code editor themes ([#4609](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4609)) +- [Legacy Maps] Fix dark mode style overrides ([#4658](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4658)) ### 🚞 Infrastructure @@ -35,26 +41,115 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 📝 Documentation - [Doc] Add COMMUNICATIONS.md with info about Slack, forum, office hours ([#3837](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3837)) -- [Saved Object Service] Adds design doc for new Saved Object Service Interface for Custom Repository [#3954](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3954) +- Add plugin development section in DEVELOPER_GUIDE.md ([#3989](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3989)) +- [Vis Augmenter] Add documentation to `vis_augmenter` plugin ([#4527](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4527)) ### 🛠 Maintenance - Removes `minimatch` manual resolution ([#3019](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3019)) - Upgrade `vega-lite` dependency from `4.17.0` to `^5.6.0` ([#3076](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3076)). Backwards-compatible version included in v2.5.0 release. - Bump `js-yaml` from `3.14.0` to `4.1.0` ([#3770](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3770)) -- Adding @ZilongX and @Flyingliuhub as maintainers. ([#4137](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4137)) -- Add new MAINTAINERS to CODEOWNERS file. ([#4199](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4199)) +- Update webpack environment targets ([#4649](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4649)) ### 🪛 Refactoring - [Console] Remove unused ul element and its custom styling ([#3993](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3993)) - Fix EUI/OUI type errors ([#3798](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3798)) - Remove unused Sass in `tile_map` plugin ([#4110](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4110)) +- [Maps Legacy] Removed KUI usage in `maps_legacy` plugin([#3998](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3998)) +- [Markdown] Replace custom CSS styles and HTML markup with OUI components ([#4390](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4390)) +- [Vis Colors] [VisLib] Update legend colors to use OUI color palette ([#4365](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4365)) +- [Vis colors] Update legacy mapped colors in charts plugin to use `ouiPaletteColorBlind()`, Update default color in legacy visualizations to use `ouiPaletteColorBlind()[0]` ([#4398](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4398)) +- [Saved Objects Management] Add new or remove extra tags and styles ([#4069](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4069)) +- [Console] Migrate `/lib/autocomplete/` module to TypeScript ([#4148](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4148)) +- [Console] Migrate `/lib/!autocomplete/` module to TypeScript ([#4150](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4150)) +- [Dashboard] Restructure the `Dashboard` plugin folder to be more cohesive with the project ([#4575](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4575)) + +### 🔩 Tests + +## [2.9.0 - 2023-07-24](https://github.com/opensearch-project/OpenSearch-Dashboards/releases/tag/2.9.0) + +### 🛡 Security + +- Bump `joi` to v14 to avoid the possibility of prototype poisoning in a nested dependency ([#3952](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3952)) +- [CVE-2022-25883] Resolve `semver` to `7.5.3` and remove unused package ([#4411](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4411)) +- Bump tough-cookie from 4.0.0 to 4.1.3 ([#4531](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4531)) + +### 📈 Features/Enhancements + +- Add plugin manifest config to define OpenSearch plugin dependency and verify if it is installed on the cluster ([#3116](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3116)) +- Replace re2 with RegExp in timeline and add unit tests ([#3908](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3908)) +- Hide any output from use_node checking for Node compatibility ([#4237](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4237)) +- Add category option within groups for context menus ([#4144](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4144)) +- [Saved Object Service] Add Repository Factory Provider ([#4149](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4149)) +- [Sample Data] Add visual consistency dashboard to sample logs data ([#4339](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4339), [#4619](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4619)) +- [@osd/pm] Fix `file:`-linked dependencies' resolution to improve ability to test with local packages ([#4342](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4342)) +- [Multiple DataSource] Backend support for adding sample data ([#4268](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4268)) +- Add configurable defaults and overrides to uiSettings ([#4344](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4344)) +- Update header logo selection logic to match the header's theme ([#4383](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4383)) +- Introduce new fonts for the Next theme ([#4381](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4381)) +- Bump OUI to `1.1.2` to make `anomalyDetection` icon available ([#4408](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4408)) +- Add `color-scheme` to the root styling ([#4477](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4477)) +- [Multiple DataSource] Frontend support for adding sample data ([#4412](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4412)) +- Enable plugins to augment visualizations with additional data and context ([#4361](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4361)) +- Dashboard De-Angularization ([#4502](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4502)) +- New management overview page and rename stack management to dashboard management ([#4287](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4287)) +- [Vis Augmenter] Update base vis height in view events flyout ([#4535](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4535)) +- [Dashboard De-Angular] Add more unit tests for utils folder ([#4641](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4641)) + +### 🐛 Bug Fixes + +- [Chore] Update deprecated url methods (url.parse(), url.format()) ([#2910](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2910)) +- Cleanup unused url ([#3847](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3847)) +- Fix `i18n` generation scripts ([#4252](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4252)) +- [Saved Objects Management] Fix relationships header overflow ([#4070](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4070)) +- Update main menu to display 'Dashboards' for consistency ([#4453](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4453)) +- [Multiple DataSource] Retain the original sample data API ([#4526](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4526)) +- Remove `lmdb-store` to fix backport issue ([#4266](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4266)) + +### 🚞 Infrastructure + +- Upgrade the backport workflow ([#4343](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4343)) +- [Lint] Add custom stylelint rules and config to prevent unintended style overrides ([#4290](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4290)) +- [Lint] Add stylelint rule to define properties that are restricted from being used ([#4374](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4374)) +- [Lint] Add typing to Stylelint rules ([#4392](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4392)) +- [CI] Split build and verify into parallel jobs ([#4467](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4467)) + +### 📝 Documentation + +- [Saved Object Service] Adds design doc for new Saved Object Service Interface for Custom Repository [#3954](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3954) + +### 🛠 Maintenance + +- Adding @ZilongX and @Flyingliuhub as maintainers. ([#4137](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4137)) +- Add new MAINTAINERS to CODEOWNERS file. ([#4199](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4199)) +- Adding @BSFishy as maintainer. ([#4469](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4469)) + +### 🪛 Refactoring + - [Table Visualization] Remove custom styling for text-align:center in favor of OUI utility class. ([#4164](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4164)) +- [Table Visualization] Replace div containers with OuiFlex components ([#4272](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4272)) +- Migrate from legacy elasticsearch client to opensearch-js client in `osd-opensearch-archiver` package([#4142](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4142)) +- Replace the use of `bluebird` in `saved_objects` plugin ([#4026](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4026)) +- Relocate tutorials imagery into `src/plugins/home/public/assets/tutorials/logos` ([#4382](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4382)) +- [VisBuilder] Use OUI icon ([#4446](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4446)) +- [Vis Colors] [Region Maps] Replace hardcode color to OUI color in `region_map` plugin ([#4299](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4299)) +- [Vis Colors] Replace color maps with OUI color palettes ([#4293](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4293)) +- [Vis Colors] [Maps] Replace hardcoded color to OUI color in `maps_legacy` plugin ([#4294](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4294)) +- [Vis Colors] [TSVB] Update default color in `vis_type_timeseries` to use `ouiPaletteColorBlind()[0]`([#4363](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4363)) +- [Vis Colors] [Timeline] Replace `vis_type_timeline` colors with `ouiPaletteColorBlind()` ([#4366](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4366)) +- [Vis Colors] Update legacy seed colors to use `ouiPaletteColorBlind()` ([#4348](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4348)) +- [Console] Migrate `/lib/mappings/` module to TypeScript ([#4008](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4008)) +- [Console] Migrate `/lib/autocomplete/` module to TypeScript ([#4148](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4148)) +- [Dashboard] Restructure the `Dashboard` plugin folder to be more cohesive with the project ([#4575](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4575)) +- [Chrome] Remove breadcrumb style overrrides ([#4621](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4621)) ### 🔩 Tests -## [2.8.0 - TBD](https://github.com/opensearch-project/OpenSearch-Dashboards/releases/tag/2.8.0) +- [Vis Augmenter Add UT for few fns ([#4516](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4516)) +- [BWC Tests] Add BWC tests for 2.7.0 and 2.8.0 ([#4023](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4023)) + +## [2.8.0 - 2023-06-06](https://github.com/opensearch-project/OpenSearch-Dashboards/releases/tag/2.8.0) ### Deprecations @@ -149,6 +244,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Monaco editor] Add json worker support ([#3424](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3424)) - [Multiple DataSource] Allow create and distinguish index pattern with same name but from different datasources ([#3604](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3604)) - [Multiple DataSource] Integrate multiple datasource with dev tool console ([#3754](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3754)) +- [Navigation] Remove unused tags ([#3964](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3964)) - [Notifications] Add id to toast api for deduplication ([#3752](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3752)) - [UI] Add support for comma delimiters in the global filter bar ([#3686](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3686)) - [UI] Indicate that IE is no longer supported ([#3641](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3641)) @@ -217,6 +313,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Update caniuse to `1.0.30001460` to fix failed integration tests ([#3538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3538)) - [Tests] Fix unit tests for `get_keystore` ([#3854](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3854)) +- [BWC Tests] Add BWC tests for 2.7.0 and 2.8.0 ([#4023](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4023)) ## [1.3.9 - 2023-04-04](https://github.com/opensearch-project/OpenSearch-Dashboards/releases/tag/1.3.9) diff --git a/COMMUNICATIONS.md b/COMMUNICATIONS.md index c1dbfc114ce7..00e2da1a58c9 100644 --- a/COMMUNICATIONS.md +++ b/COMMUNICATIONS.md @@ -36,7 +36,7 @@ While we'll always prioritize asynchronous communication, sometimes a community 1. Review a proposal or technical design for a new feature in OpenSearch Dashboards or an OpenSearch Dashboards plugin 2. Learn more about how to build and extend OpenSearch Dashboards - which APIs, plugins, resources, and services are available to speed development -3. Discuss OpenSearch Dashboard roadmap and technical initiatives +3. Discuss OpenSearch Dashboards roadmap and technical initiatives Signing up isn't required to attend - all OpenSearch Dashboards contributors or interested developers are welcome as participants. diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 3df2106e9678..ac26f4bcd8b2 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -13,6 +13,7 @@ This guide applies to all development within the OpenSearch Dashboards project a - [Next Steps](#next-steps) - [Alternative development installations](#alternative-development-installations) - [Optional - Run OpenSearch with plugins](#optional---run-opensearch-with-plugins) + - [Plugin development](#plugin-development) - [Alternative - Run OpenSearch from tarball](#alternative---run-opensearch-from-tarball) - [Configure OpenSearch Dashboards for security](#configure-opensearch-dashboards-for-security) - [Building artifacts](#building-artifacts) @@ -231,6 +232,9 @@ $ yarn opensearch snapshot --P https://repo1.maven.org/maven2/org/opensearch/plu Note - if you add the [`security` plugin](https://github.com/opensearch-project/security), you'll also need to [configure OpenSearch Dashboards for security](#configure-opensearch-dashboards-for-security). +### Plugin development +The osd-plugin-generator tool makes it easier to create a plugin for OpenSearch Dashboards. It sets up the basic structure of the project and provides scripts to build it. Refer to [osd-plugin-generator](https://github.com/opensearch-project/OpenSearch-Dashboards/tree/main/packages/osd-plugin-generator) for more details. + #### Other snapshot configuration options Additional options can be passed after `yarn opensearch snapshot` to further configure the cluster snapshot. diff --git a/MAINTAINERS.md b/MAINTAINERS.md index ae42e47b014b..1deb190bdd19 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -19,11 +19,12 @@ This document contains a list of maintainers in this repo. See [opensearch-proje | Manasvini B Suryanarayana | [manasvinibs](https://github.com/manasvinibs) | Amazon | | Tao Liu | [Flyingliuhub](https://github.com/Flyingliuhub) | Amazon | | Zilong Xia | [ZilongX](https://github.com/ZilongX) | Amazon | +| Matt Provost | [BSFishy](https://github.com/BSFishy) | Amazon | ## Emeritus -| Maintainer | GitHub ID | Affiliation | -| ------------- | --------------------------------------- | ----------- | -| Tommy Markley | [tmarkley](https://github.com/tmarkley) | Amazon | +| Maintainer | GitHub ID | Affiliation | +| ------------- | ----------------------------------------- | ----------- | +| Tommy Markley | [tmarkley](https://github.com/tmarkley) | Amazon | | Mihir Soni | [mihirsoni](https://github.com/mihirsoni) | Amazon | -| Bishoy Boktor | [boktorbb](https://github.com/boktorbb) | Amazon | +| Bishoy Boktor | [boktorbb](https://github.com/boktorbb) | Amazon | diff --git a/README.md b/README.md index 5c6c764f87f6..70bc8200f61c 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ Copyright OpenSearch Contributors. See [NOTICE](NOTICE.txt) for details. [codecov-badge]: https://codecov.io/gh/opensearch-project/OpenSearch-Dashboards/branch/main/graphs/badge.svg [codecov-link]: https://app.codecov.io/gh/opensearch-project/OpenSearch-Dashboards [link-checker-badge]: https://github.com/opensearch-project/OpenSearch-Dashboards/actions/workflows/links_checker.yml/badge.svg -[link-checker-link]: https://github.com/opensearch-project/OpenSearch-Dashboards/actions/workflows/links_checker.yml +[link-checker-link]: https://github.com/opensearch-project/OpenSearch-Dashboards/actions/workflows/links_checker.yml \ No newline at end of file diff --git a/TESTING.md b/TESTING.md index 23866aede01c..95dc9495309a 100644 --- a/TESTING.md +++ b/TESTING.md @@ -35,6 +35,8 @@ To run all the unit tests: `yarn test:jest` To run specific unit tests, pass the path to the test: `yarn test:jest [test path]` +To run specific unit test groups: +`yarn test:jest --ci-group=1 --ci-group=2` ### Integration tests To run all the integration tests: diff --git a/bwctest.sh b/bwctest.sh index 1b44d15b64cf..f85764f9f68b 100755 --- a/bwctest.sh +++ b/bwctest.sh @@ -13,7 +13,7 @@ set -e -DEFAULT_VERSIONS="osd-2.0.0,osd-2.1.0,osd-2.2.0,osd-2.3.0,osd-2.4.0,osd-2.5.0" +DEFAULT_VERSIONS="osd-2.0.0,osd-2.1.0,osd-2.2.0,osd-2.3.0,osd-2.4.0,osd-2.5.0,osd-2.6.0,osd-2.7.0" function usage() { echo "" diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index d7e0d390b0fc..73f31233a783 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -264,3 +264,7 @@ # 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" + +# Set the value of this setting to true to enable plugin augmentation on Dashboard +# vis_augmenter.pluginAugmentationEnabled: true + diff --git a/cypress/integration/with-security/helpers/generate_data.js b/cypress/integration/with-security/helpers/generate_data.js index 4833a81a1398..dcd711fc7c18 100755 --- a/cypress/integration/with-security/helpers/generate_data.js +++ b/cypress/integration/with-security/helpers/generate_data.js @@ -84,6 +84,7 @@ describe('Generating BWC test data with security', () => { }); // update default expression to use `.es(*)` instead of `.opensearch(*)` for bwc cy.get('[class="view-line"]').type('.es(*)'); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); cy.get('[data-test-subj="visualizeSaveButton"]').click(); cy.get('[data-test-subj="savedObjectTitle"]').type('test-timeline'); cy.get('[data-test-subj="confirmSaveSavedObjectButton"]').click(); diff --git a/cypress/integration/without-security/helpers/generate_data.js b/cypress/integration/without-security/helpers/generate_data.js index 4f2962769c16..47e9c2f5f5ed 100755 --- a/cypress/integration/without-security/helpers/generate_data.js +++ b/cypress/integration/without-security/helpers/generate_data.js @@ -67,6 +67,7 @@ describe('Generating BWC test data without security', () => { }); // update default expression to use `.es(*)` instead of `.opensearch(*)` for bwc cy.get('[class="view-line"]').type('.es(*)'); + cy.get('[data-test-subj="visualizeEditorRenderButton"]').click(); cy.get('[data-test-subj="visualizeSaveButton"]').click(); cy.get('[data-test-subj="savedObjectTitle"]').type('test-timeline'); cy.get('[data-test-subj="confirmSaveSavedObjectButton"]').click(); diff --git a/cypress/test-data/without-security/osd-2.6.0.tar.gz b/cypress/test-data/without-security/osd-2.6.0.tar.gz new file mode 100644 index 000000000000..82f8ba26f05c Binary files /dev/null and b/cypress/test-data/without-security/osd-2.6.0.tar.gz differ diff --git a/cypress/test-data/without-security/osd-2.7.0.tar.gz b/cypress/test-data/without-security/osd-2.7.0.tar.gz new file mode 100644 index 000000000000..d8866f6035b8 Binary files /dev/null and b/cypress/test-data/without-security/osd-2.7.0.tar.gz differ diff --git a/examples/ui_actions_explorer/public/context_menu_examples/context_menu_examples.tsx b/examples/ui_actions_explorer/public/context_menu_examples/context_menu_examples.tsx index b01d04c1608b..1f6ba03e966b 100644 --- a/examples/ui_actions_explorer/public/context_menu_examples/context_menu_examples.tsx +++ b/examples/ui_actions_explorer/public/context_menu_examples/context_menu_examples.tsx @@ -36,6 +36,7 @@ import { PanelViewWithSharingLong } from './panel_view_with_sharing_long'; import { PanelEdit } from './panel_edit'; import { PanelEditWithDrilldowns } from './panel_edit_with_drilldowns'; import { PanelEditWithDrilldownsAndContextActions } from './panel_edit_with_drilldowns_and_context_actions'; +import { PanelGroupOptionsAndContextActions } from './panel_group_options_and_context_actions'; export const ContextMenuExamples: React.FC = () => { return ( @@ -59,7 +60,6 @@ export const ContextMenuExamples: React.FC = () => { - @@ -71,6 +71,11 @@ export const ContextMenuExamples: React.FC = () => { + + + + + ); }; diff --git a/examples/ui_actions_explorer/public/context_menu_examples/panel_group_options_and_context_actions.tsx b/examples/ui_actions_explorer/public/context_menu_examples/panel_group_options_and_context_actions.tsx new file mode 100644 index 000000000000..20dc73406c55 --- /dev/null +++ b/examples/ui_actions_explorer/public/context_menu_examples/panel_group_options_and_context_actions.tsx @@ -0,0 +1,83 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as React from 'react'; +import { EuiButton, EuiContextMenu, EuiPopover } from '@elastic/eui'; +import useAsync from 'react-use/lib/useAsync'; +import { buildContextMenuForActions, Action } from '../../../../src/plugins/ui_actions/public'; +import { sampleAction } from './util'; + +export const PanelGroupOptionsAndContextActions: React.FC = () => { + const [open, setOpen] = React.useState(false); + + const context = {}; + const trigger: any = 'TEST_TRIGGER'; + const drilldownGrouping: Action['grouping'] = [ + { + id: 'drilldowns', + getDisplayName: () => 'Uncategorized group', + getIconType: () => 'popout', + order: 20, + }, + ]; + const exampleGroup: Action['grouping'] = [ + { + id: 'example', + getDisplayName: () => 'Example group', + getIconType: () => 'cloudStormy', + order: 20, + category: 'visAug', + }, + ]; + const alertingGroup: Action['grouping'] = [ + { + id: 'alerting', + getDisplayName: () => 'Alerting', + getIconType: () => 'cloudStormy', + order: 20, + category: 'visAug', + }, + ]; + const anomaliesGroup: Action['grouping'] = [ + { + id: 'anomalies', + getDisplayName: () => 'Anomalies', + getIconType: () => 'cloudStormy', + order: 30, + category: 'visAug', + }, + ]; + const actions = [ + sampleAction('test-1', 100, 'Edit visualization', 'pencil'), + sampleAction('test-2', 99, 'Clone panel', 'partial'), + + sampleAction('test-9', 10, 'Create drilldown', 'plusInCircle', drilldownGrouping), + sampleAction('test-10', 9, 'Manage drilldowns', 'list', drilldownGrouping), + + sampleAction('test-11', 10, 'Example action', 'dashboardApp', exampleGroup), + sampleAction('test-11', 10, 'Alertin action 1', 'dashboardApp', alertingGroup), + sampleAction('test-12', 9, 'Alertin action 2', 'dashboardApp', alertingGroup), + sampleAction('test-13', 8, 'Anomalies 1', 'cloudStormy', anomaliesGroup), + sampleAction('test-14', 7, 'Anomalies 2', 'link', anomaliesGroup), + ]; + + const panels = useAsync(() => + buildContextMenuForActions({ + actions: actions.map((action) => ({ action, context, trigger })), + }) + ); + + return ( + setOpen((x) => !x)}>Grouping with categories} + isOpen={open} + panelPaddingSize="none" + anchorPosition="downLeft" + closePopover={() => setOpen(false)} + > + + + ); +}; diff --git a/package.json b/package.json index 30e6756ca108..decb8f5f37b5 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "**/unset-value": "^2.0.1", "**/jest-config": "npm:@amoo-miki/jest-config@27.5.1", "**/jest-jasmine2": "npm:@amoo-miki/jest-jasmine2@27.5.1", + "**/semver": "^7.5.3", "**/set-value": "^4.1.0", "**/xml2js": "^0.5.0", "**/yaml": "^2.2.2" @@ -121,7 +122,7 @@ "dependencies": { "@aws-crypto/client-node": "^3.1.1", "@elastic/datemath": "5.0.3", - "@elastic/eui": "npm:@opensearch-project/oui@1.1.1", + "@elastic/eui": "npm:@opensearch-project/oui@1.3.0-alpha.2", "@elastic/good": "^9.0.1-kibana3", "@elastic/numeral": "^2.5.0", "@elastic/request-crypto": "2.0.0", @@ -170,7 +171,6 @@ "dns-sync": "^0.2.1", "elastic-apm-node": "^3.43.0", "elasticsearch": "^16.7.0", - "http-aws-es": "npm:@zhongnansu/http-aws-es@6.0.1", "execa": "^4.0.2", "expiry-js": "0.1.7", "fast-deep-equal": "^3.1.1", @@ -181,6 +181,7 @@ "globby": "^11.1.0", "handlebars": "4.7.7", "hjson": "3.2.1", + "http-aws-es": "npm:@zhongnansu/http-aws-es@6.0.1", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^5.0.0", "inline-style": "^2.0.0", @@ -211,7 +212,7 @@ "require-in-the-middle": "^5.0.2", "rison-node": "1.0.2", "rxjs": "^6.5.5", - "semver": "^5.7.0", + "semver": "^7.5.3", "set-value": "^4.1.0", "source-map-support": "^0.5.19", "symbol-observable": "^1.2.0", @@ -248,6 +249,8 @@ "@osd/optimizer": "1.0.0", "@osd/plugin-generator": "1.0.0", "@osd/pm": "1.0.0", + "@osd/stylelint-config": "1.0.0", + "@osd/stylelint-plugin-stylelint": "1.0.0", "@osd/telemetry-tools": "1.0.0", "@osd/test": "1.0.0", "@osd/test-subj-selector": "0.2.1", @@ -287,6 +290,7 @@ "@types/has-ansi": "^3.0.0", "@types/history": "^4.7.3", "@types/hjson": "^2.4.2", + "@types/http-aws-es": "6.0.2", "@types/jest": "^27.4.0", "@types/joi": "^13.4.2", "@types/jquery": "^3.3.31", @@ -320,7 +324,7 @@ "@types/react-virtualized": "^9.18.7", "@types/recompose": "^0.30.6", "@types/selenium-webdriver": "^4.0.9", - "@types/semver": "^5.5.0", + "@types/semver": "^7.5.0", "@types/sinon": "^7.0.13", "@types/strip-ansi": "^5.2.1", "@types/styled-components": "^5.1.19", @@ -339,7 +343,6 @@ "@types/zen-observable": "^0.8.0", "@typescript-eslint/eslint-plugin": "^3.10.0", "@typescript-eslint/parser": "^3.10.0", - "@types/http-aws-es": "6.0.2", "angular-aria": "^1.8.0", "angular-mocks": "^1.8.2", "angular-recursion": "^1.0.5", @@ -454,7 +457,7 @@ "supertest-as-promised": "^4.0.2", "tape": "^5.0.1", "topojson-client": "3.0.0", - "tough-cookie": "^4.0.0", + "tough-cookie": "^4.1.3", "tree-kill": "^1.2.2", "typescript": "4.0.2", "ui-select": "0.19.8", diff --git a/packages/osd-babel-preset/node_preset.js b/packages/osd-babel-preset/node_preset.js index 0acb1e146bdd..43915e239c38 100644 --- a/packages/osd-babel-preset/node_preset.js +++ b/packages/osd-babel-preset/node_preset.js @@ -40,7 +40,7 @@ module.exports = (_, options = {}) => { // `nvm install 8 && node ./src/cli` will run OpenSearch Dashboards // in node version 8 and babel will stop transpiling async/await // because they are supported in the "current" version of node - node: 'current', + node: 14, }, // replaces `import "core-js/stable"` with a list of require statements diff --git a/packages/osd-babel-preset/package.json b/packages/osd-babel-preset/package.json index d24b959c641c..b471529bbda0 100644 --- a/packages/osd-babel-preset/package.json +++ b/packages/osd-babel-preset/package.json @@ -19,7 +19,11 @@ "babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-styled-components": "^2.0.2", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", + "browserslist": "^4.21.10", "react-is": "^16.8.0", "styled-components": "^5.3.9" + }, + "devDependencies": { + "@types/browserslist": "^4.15.0" } } diff --git a/packages/osd-babel-preset/webpack_preset.js b/packages/osd-babel-preset/webpack_preset.js index d1ee5c3cb19a..9d0a75a042c5 100644 --- a/packages/osd-babel-preset/webpack_preset.js +++ b/packages/osd-babel-preset/webpack_preset.js @@ -28,6 +28,10 @@ * under the License. */ +const { resolve } = require('path'); +const browserlist = require('browserslist'); +const targets = browserlist.loadConfig({ path: resolve(__dirname, '../..') }); + module.exports = () => { return { presets: [ @@ -36,6 +40,7 @@ module.exports = () => { { useBuiltIns: 'entry', modules: false, + targets, // Please read the explanation for this // in node_preset.js corejs: '3.2.1', diff --git a/packages/osd-interpreter/package.json b/packages/osd-interpreter/package.json index 6d11eb3bc1ee..5667f0661e1f 100644 --- a/packages/osd-interpreter/package.json +++ b/packages/osd-interpreter/package.json @@ -27,7 +27,7 @@ "del": "^6.1.1", "getopts": "^2.2.5", "pegjs": "0.10.0", - "sass-loader": "^10.4.1", + "sass-loader": "npm:@amoo-miki/sass-loader@10.4.1-node-sass-9.0.0-libsass-3.6.5", "style-loader": "^1.1.3", "supports-color": "^7.0.0", "url-loader": "^2.2.0", diff --git a/packages/osd-opensearch-archiver/package.json b/packages/osd-opensearch-archiver/package.json index 8f88fa879525..1c036dc10c50 100644 --- a/packages/osd-opensearch-archiver/package.json +++ b/packages/osd-opensearch-archiver/package.json @@ -12,9 +12,7 @@ }, "dependencies": { "@osd/dev-utils": "1.0.0", - "elasticsearch": "^16.7.0" + "@opensearch-project/opensearch": "^2.2.0" }, - "devDependencies": { - "@types/elasticsearch": "^5.0.33" - } + "devDependencies": {} } diff --git a/packages/osd-opensearch-archiver/src/actions/empty_opensearch_dashboards_index.ts b/packages/osd-opensearch-archiver/src/actions/empty_opensearch_dashboards_index.ts index e0b23ac8088f..2f7ba1f22fd0 100644 --- a/packages/osd-opensearch-archiver/src/actions/empty_opensearch_dashboards_index.ts +++ b/packages/osd-opensearch-archiver/src/actions/empty_opensearch_dashboards_index.ts @@ -28,7 +28,7 @@ * under the License. */ -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog, OsdClient } from '@osd/dev-utils'; import { diff --git a/packages/osd-opensearch-archiver/src/actions/load.ts b/packages/osd-opensearch-archiver/src/actions/load.ts index f513d049dbd1..65297501264a 100644 --- a/packages/osd-opensearch-archiver/src/actions/load.ts +++ b/packages/osd-opensearch-archiver/src/actions/load.ts @@ -32,7 +32,7 @@ import { resolve } from 'path'; import { createReadStream } from 'fs'; import { Readable } from 'stream'; import { ToolingLog, OsdClient } from '@osd/dev-utils'; -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { createPromiseFromStreams, concatStreamProviders } from '../lib/streams'; @@ -114,7 +114,7 @@ export async function loadAction({ await client.indices.refresh({ index: '_all', - allowNoIndices: true, + allow_no_indices: true, }); // If we affected the OpenSearch Dashboards index, we need to ensure it's migrated... diff --git a/packages/osd-opensearch-archiver/src/actions/save.ts b/packages/osd-opensearch-archiver/src/actions/save.ts index 46f2103f8f51..5e5b0d310d5c 100644 --- a/packages/osd-opensearch-archiver/src/actions/save.ts +++ b/packages/osd-opensearch-archiver/src/actions/save.ts @@ -31,7 +31,7 @@ import { resolve } from 'path'; import { createWriteStream, mkdirSync } from 'fs'; import { Readable, Writable } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog } from '@osd/dev-utils'; import { createListStream, createPromiseFromStreams } from '../lib/streams'; diff --git a/packages/osd-opensearch-archiver/src/actions/unload.ts b/packages/osd-opensearch-archiver/src/actions/unload.ts index 3e2bb4c8535d..6896b7878c6f 100644 --- a/packages/osd-opensearch-archiver/src/actions/unload.ts +++ b/packages/osd-opensearch-archiver/src/actions/unload.ts @@ -31,7 +31,7 @@ import { resolve } from 'path'; import { createReadStream } from 'fs'; import { Readable, Writable } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog, OsdClient } from '@osd/dev-utils'; import { createPromiseFromStreams } from '../lib/streams'; diff --git a/packages/osd-opensearch-archiver/src/cli.ts b/packages/osd-opensearch-archiver/src/cli.ts index 002e3e287587..e8606ed26645 100644 --- a/packages/osd-opensearch-archiver/src/cli.ts +++ b/packages/osd-opensearch-archiver/src/cli.ts @@ -38,8 +38,8 @@ import Path from 'path'; import readline from 'readline'; import { RunWithCommands, createFlagError } from '@osd/dev-utils'; +import { Client, ClientOptions } from '@opensearch-project/opensearch'; import { readConfigFile } from '@osd/test'; -import legacyElasticsearch from 'elasticsearch'; import { OpenSearchArchiver } from './opensearch_archiver'; @@ -56,7 +56,7 @@ export function runCli() { default: ${defaultConfigPath} --opensearch-url url for OpenSearch, prefer the --config flag --opensearch-dashboards-url url for OpenSearch Dashboards, prefer the --config flag - --dir where arechives are stored, prefer the --config flag + --dir where archives are stored, prefer the --config flag `, }, async extendContext({ log, flags, addCleanupTask }) { @@ -99,10 +99,11 @@ export function runCli() { throw createFlagError('--dir or --config must be defined'); } - const client = new legacyElasticsearch.Client({ - host: opensearchUrl, - log: flags.verbose ? 'trace' : [], - }); + const clientOptions: ClientOptions = { + node: opensearchUrl.toString(), + }; + + const client = new Client(clientOptions); addCleanupTask(() => client.close()); const opensearchArchiver = new OpenSearchArchiver({ diff --git a/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.test.ts b/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.test.ts index 462aba6c234a..603bfc278e2d 100644 --- a/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.test.ts +++ b/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.test.ts @@ -47,9 +47,11 @@ describe('opensearchArchiver: createGenerateDocRecordsStream()', () => { expect(params).to.have.property('index', 'logstash-*'); expect(params).to.have.property('size', 1000); return { - hits: { - total: 0, - hits: [], + body: { + hits: { + total: 0, + hits: [], + }, }, }; }, @@ -74,9 +76,11 @@ describe('opensearchArchiver: createGenerateDocRecordsStream()', () => { expect(params).to.have.property('scroll', '1m'); expect(params).to.have.property('rest_total_hits_as_int', true); return { - hits: { - total: 0, - hits: [], + body: { + hits: { + total: 0, + hits: [], + }, }, }; }, @@ -101,17 +105,19 @@ describe('opensearchArchiver: createGenerateDocRecordsStream()', () => { expect(params).to.have.property('index', 'index1'); await delay(200); return { - _scroll_id: 'index1ScrollId', - hits: { total: 2, hits: [{ _id: 1, _index: '.opensearch_dashboards_1' }] }, + body: { + _scroll_id: 'index1ScrollId', + hits: { total: 2, hits: [{ _id: 1, _index: '.opensearch_dashboards_1' }] }, + }, }; }, async (name, params) => { expect(name).to.be('scroll'); - expect(params).to.have.property('scrollId', 'index1ScrollId'); + expect(params).to.have.property('scroll_id', 'index1ScrollId'); expect(Date.now() - checkpoint).to.not.be.lessThan(200); checkpoint = Date.now(); await delay(200); - return { hits: { total: 2, hits: [{ _id: 2, _index: 'foo' }] } }; + return { body: { hits: { total: 2, hits: [{ _id: 2, _index: 'foo' }] } } }; }, async (name, params) => { expect(name).to.be('search'); @@ -119,7 +125,7 @@ describe('opensearchArchiver: createGenerateDocRecordsStream()', () => { expect(Date.now() - checkpoint).to.not.be.lessThan(200); checkpoint = Date.now(); await delay(200); - return { hits: { total: 0, hits: [] } }; + return { body: { hits: { total: 0, hits: [] } } }; }, ]); diff --git a/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.ts b/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.ts index 6949e2b4d4ff..9bbb99898600 100644 --- a/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.ts +++ b/packages/osd-opensearch-archiver/src/lib/docs/generate_doc_records_stream.ts @@ -29,7 +29,7 @@ */ import { Transform } from 'stream'; -import { Client, SearchParams, SearchResponse } from 'elasticsearch'; +import { Client, ApiResponse } from '@opensearch-project/opensearch'; import { Stats } from '../stats'; import { Progress } from '../progress'; @@ -53,7 +53,7 @@ export function createGenerateDocRecordsStream({ async transform(index, enc, callback) { try { let remainingHits = 0; - let resp: SearchResponse | null = null; + let resp: ApiResponse | null = null; while (!resp || remainingHits > 0) { if (!resp) { @@ -66,17 +66,17 @@ export function createGenerateDocRecordsStream({ query, }, rest_total_hits_as_int: true, // not declared on SearchParams type - } as SearchParams); - remainingHits = resp.hits.total; + }); + remainingHits = resp.body.hits.total; progress.addToTotal(remainingHits); } else { resp = await client.scroll({ - scrollId: resp._scroll_id!, + scroll_id: resp.body._scroll_id!, scroll: SCROLL_TIMEOUT, }); } - for (const hit of resp.hits.hits) { + for (const hit of resp.body?.hits.hits) { remainingHits -= 1; stats.archivedDoc(hit._index); this.push({ @@ -94,7 +94,7 @@ export function createGenerateDocRecordsStream({ }); } - progress.addToComplete(resp.hits.hits.length); + progress.addToComplete(resp.body.hits.hits.length); } callback(undefined); diff --git a/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.test.ts b/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.test.ts index 00b9e22660ca..313fdf3589ed 100644 --- a/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.test.ts +++ b/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.test.ts @@ -63,11 +63,12 @@ describe('opensearchArchiver: createIndexDocRecordsStream()', () => { const client = createStubClient([ async (name, params) => { expect(name).to.be('bulk'); - expect(params).to.eql({ - body: recordsToBulkBody(records), - requestTimeout: 120000, - }); - return { ok: true }; + expect(params).to.eql({ body: recordsToBulkBody(records) }); + return { + body: { + ok: true, + }, + }; }, ]); const stats = createStubStats(); @@ -88,19 +89,21 @@ describe('opensearchArchiver: createIndexDocRecordsStream()', () => { const client = createStubClient([ async (name, params) => { expect(name).to.be('bulk'); - expect(params).to.eql({ - body: recordsToBulkBody(records.slice(0, 1)), - requestTimeout: 120000, - }); - return { ok: true }; + expect(params).to.eql({ body: recordsToBulkBody(records.slice(0, 1)) }); + return { + body: { + ok: true, + }, + }; }, async (name, params) => { expect(name).to.be('bulk'); - expect(params).to.eql({ - body: recordsToBulkBody(records.slice(1)), - requestTimeout: 120000, - }); - return { ok: true }; + expect(params).to.eql({ body: recordsToBulkBody(records.slice(1)) }); + return { + body: { + ok: true, + }, + }; }, ]); const stats = createStubStats(); @@ -124,21 +127,23 @@ describe('opensearchArchiver: createIndexDocRecordsStream()', () => { const client = createStubClient([ async (name, params) => { expect(name).to.be('bulk'); - expect(params).to.eql({ - body: recordsToBulkBody(records.slice(0, 1)), - requestTimeout: 120000, - }); + expect(params).to.eql({ body: recordsToBulkBody(records.slice(0, 1)) }); await delay(delayMs); - return { ok: true }; + return { + body: { + ok: true, + }, + }; }, async (name, params) => { expect(name).to.be('bulk'); - expect(params).to.eql({ - body: recordsToBulkBody(records.slice(1)), - requestTimeout: 120000, - }); + expect(params).to.eql({ body: recordsToBulkBody(records.slice(1)) }); expect(Date.now() - start).to.not.be.lessThan(delayMs); - return { ok: true }; + return { + body: { + ok: true, + }, + }; }, ]); const progress = new Progress(); @@ -160,17 +165,29 @@ describe('opensearchArchiver: createIndexDocRecordsStream()', () => { async (name, params) => { expect(name).to.be('bulk'); expect(params.body.length).to.eql(1 * 2); - return { ok: true }; + return { + body: { + ok: true, + }, + }; }, async (name, params) => { expect(name).to.be('bulk'); expect(params.body.length).to.eql(299 * 2); - return { ok: true }; + return { + body: { + ok: true, + }, + }; }, async (name, params) => { expect(name).to.be('bulk'); expect(params.body.length).to.eql(1 * 2); - return { ok: true }; + return { + body: { + ok: true, + }, + }; }, ]); const progress = new Progress(); @@ -189,8 +206,8 @@ describe('opensearchArchiver: createIndexDocRecordsStream()', () => { const records = createPersonDocRecords(2); const stats = createStubStats(); const client = createStubClient([ - async () => ({ ok: true }), - async () => ({ errors: true, forcedError: true }), + async () => ({ body: { ok: true } }), + async () => ({ body: { errors: true, forcedError: true } }), ]); const progress = new Progress(); diff --git a/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.ts b/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.ts index d1ba68f7bf05..4fe7059b8464 100644 --- a/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.ts +++ b/packages/osd-opensearch-archiver/src/lib/docs/index_doc_records_stream.ts @@ -28,7 +28,7 @@ * under the License. */ -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { Writable } from 'stream'; import { Stats } from '../stats'; import { Progress } from '../progress'; @@ -58,8 +58,8 @@ export function createIndexDocRecordsStream( ); }); - const resp = await client.bulk({ requestTimeout: 2 * 60 * 1000, body }); - if (resp.errors) { + const resp = await client.bulk({ body }, { requestTimeout: 2 * 60 * 1000 }); + if (resp.body.errors) { throw new Error(`Failed to index all documents: ${JSON.stringify(resp, null, 2)}`); } } diff --git a/packages/osd-opensearch-archiver/src/lib/docs/test_stubs.ts b/packages/osd-opensearch-archiver/src/lib/docs/test_stubs.ts index 27b5803cc31b..5630f95ba143 100644 --- a/packages/osd-opensearch-archiver/src/lib/docs/test_stubs.ts +++ b/packages/osd-opensearch-archiver/src/lib/docs/test_stubs.ts @@ -28,7 +28,7 @@ * under the License. */ -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import sinon from 'sinon'; import Chance from 'chance'; import { times } from 'lodash'; diff --git a/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.test.ts b/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.test.ts index 200a6a79f965..b78f8aa51411 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.test.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.test.ts @@ -83,7 +83,6 @@ describe('opensearchArchiver: createCreateIndexStream()', () => { expect((client.indices.getAlias as sinon.SinonSpy).calledOnce).to.be.ok(); expect((client.indices.getAlias as sinon.SinonSpy).args[0][0]).to.eql({ name: 'existing-index', - ignore: [404], }); expect((client.indices.delete as sinon.SinonSpy).calledOnce).to.be.ok(); expect((client.indices.delete as sinon.SinonSpy).args[0][0]).to.eql({ diff --git a/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.ts b/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.ts index 6154f0382a96..7427f8e7ae21 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/create_index_stream.ts @@ -31,7 +31,7 @@ import { Transform, Readable } from 'stream'; import { inspect } from 'util'; -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog } from '@osd/dev-utils'; import { Stats } from '../stats'; diff --git a/packages/osd-opensearch-archiver/src/lib/indices/delete_index.ts b/packages/osd-opensearch-archiver/src/lib/indices/delete_index.ts index ee8fe10d8d0b..93c8f4fdd039 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/delete_index.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/delete_index.ts @@ -29,7 +29,7 @@ */ import { get } from 'lodash'; -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog } from '@osd/dev-utils'; import { Stats } from '../stats'; @@ -46,8 +46,8 @@ export async function deleteIndex(options: { const { client, stats, index, log, retryIfSnapshottingCount = 10 } = options; const getIndicesToDelete = async () => { - const aliasInfo = await client.indices.getAlias({ name: index, ignore: [404] }); - return aliasInfo.status === 404 ? [index] : Object.keys(aliasInfo); + const { body, statusCode } = await client.indices.getAlias({ name: index }, { ignore: [404] }); + return statusCode === 404 ? [index] : Object.keys(body); }; try { @@ -92,7 +92,9 @@ export function isDeleteWhileSnapshotInProgressError(error: object) { export async function waitForSnapshotCompletion(client: Client, index: string, log: ToolingLog) { const isSnapshotPending = async (repository: string, snapshot: string) => { const { - snapshots: [status], + body: { + snapshots: [status], + }, } = await client.snapshot.status({ repository, snapshot, @@ -103,7 +105,9 @@ export async function waitForSnapshotCompletion(client: Client, index: string, l }; const getInProgressSnapshots = async (repository: string) => { - const { snapshots: inProgressSnapshots } = await client.snapshot.get({ + const { + body: { snapshots: inProgressSnapshots }, + } = await client.snapshot.get({ repository, snapshot: '_current', }); @@ -112,7 +116,7 @@ export async function waitForSnapshotCompletion(client: Client, index: string, l for (const repository of Object.keys(await client.snapshot.getRepository({} as any))) { const allInProgress = await getInProgressSnapshots(repository); - const found = allInProgress.find((s: any) => s.indices.includes(index)); + const found = allInProgress?.find((s: any) => s.indices.includes(index)); if (!found) { continue; diff --git a/packages/osd-opensearch-archiver/src/lib/indices/delete_index_stream.ts b/packages/osd-opensearch-archiver/src/lib/indices/delete_index_stream.ts index b728aa35757b..fe22f31e15da 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/delete_index_stream.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/delete_index_stream.ts @@ -29,7 +29,7 @@ */ import { Transform } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog } from '@osd/dev-utils'; import { Stats } from '../stats'; diff --git a/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.test.ts b/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.test.ts index a961cca3550e..8d0b4087ea40 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.test.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.test.ts @@ -67,8 +67,8 @@ describe('opensearchArchiver: createGenerateIndexRecordsStream()', () => { ]); const params = (client.indices.get as sinon.SinonSpy).args[0][0]; - expect(params).to.have.property('filterPath'); - const filters: string[] = params.filterPath; + expect(params).to.have.property('filter_path'); + const filters: string[] = params.filter_path; expect(filters.some((path) => path.includes('index.creation_date'))).to.be(true); expect(filters.some((path) => path.includes('index.uuid'))).to.be(true); expect(filters.some((path) => path.includes('index.version'))).to.be(true); diff --git a/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.ts b/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.ts index f682af3d8598..e74965657c70 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/generate_index_records_stream.ts @@ -29,7 +29,7 @@ */ import { Transform } from 'stream'; -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { Stats } from '../stats'; export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { @@ -40,7 +40,7 @@ export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { try { const resp = (await client.indices.get({ index: indexOrAlias, - filterPath: [ + filter_path: [ '*.settings', '*.mappings', // remove settings that aren't really settings @@ -56,9 +56,10 @@ export function createGenerateIndexRecordsStream(client: Client, stats: Stats) { })) as Record; for (const [index, { settings, mappings }] of Object.entries(resp)) { + const { body, statusCode } = await client.indices.getAlias({ index }); const { [index]: { aliases }, - } = await client.indices.getAlias({ index }); + } = statusCode === 404 ? {} : body; stats.archivedIndex(index, { settings, mappings }); this.push({ diff --git a/packages/osd-opensearch-archiver/src/lib/indices/opensearch_dashboards_index.ts b/packages/osd-opensearch-archiver/src/lib/indices/opensearch_dashboards_index.ts index aff69cd2682c..9a415ebb4ee4 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/opensearch_dashboards_index.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/opensearch_dashboards_index.ts @@ -28,7 +28,7 @@ * under the License. */ -import { Client, CreateDocumentParams } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog, OsdClient } from '@osd/dev-utils'; import { Stats } from '../stats'; import { deleteIndex } from './delete_index'; @@ -52,15 +52,17 @@ export async function deleteOpenSearchDashboardsIndices({ await client.indices.putSettings({ index: indexNames, - body: { index: { blocks: { read_only: false } } }, + body: { blocks: { read_only: false } }, }); - await deleteIndex({ - client, - stats, - index: indexNames, - log, - }); + for (const indexName of indexNames) { + await deleteIndex({ + client, + stats, + index: indexName, + log, + }); + } return indexNames; } @@ -101,8 +103,8 @@ async function fetchOpenSearchDashboardsIndices(client: Client) { format: 'json', }); const isOpenSearchDashboardsIndex = (index: string) => /^\.kibana(:?_\d*)?$/.test(index); - return opensearchDashboardsIndices - .map((x: { index: string }) => x.index) + return opensearchDashboardsIndices.body + .map((x) => x.index?.toString() ?? '') .filter(isOpenSearchDashboardsIndex); } @@ -133,21 +135,19 @@ export async function cleanOpenSearchDashboardsIndices({ bool: { must_not: { ids: { - type: '_doc', values: ['space:default'], }, }, }, }, }, - ignore: [409], }); - if (resp.total !== resp.deleted) { + if (resp.body.total !== resp.body.deleted) { log.warning( 'delete by query deleted %d of %d total documents, trying again', - resp.deleted, - resp.total + resp.body.deleted, + resp.body.total ); continue; } @@ -166,9 +166,7 @@ export async function cleanOpenSearchDashboardsIndices({ export async function createDefaultSpace({ index, client }: { index: string; client: Client }) { await client.create({ index, - type: '_doc', id: 'space:default', - ignore: 409, body: { type: 'space', updated_at: new Date().toISOString(), @@ -179,5 +177,5 @@ export async function createDefaultSpace({ index, client }: { index: string; cli _reserved: true, }, }, - } as CreateDocumentParams); + }); } diff --git a/packages/osd-opensearch-archiver/src/lib/indices/test_stubs.ts b/packages/osd-opensearch-archiver/src/lib/indices/test_stubs.ts index 64b42a629cd6..bab84dd653b2 100644 --- a/packages/osd-opensearch-archiver/src/lib/indices/test_stubs.ts +++ b/packages/osd-opensearch-archiver/src/lib/indices/test_stubs.ts @@ -28,7 +28,7 @@ * under the License. */ -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import sinon from 'sinon'; import { ToolingLog } from '@osd/dev-utils'; import { Stats } from '../stats'; @@ -113,14 +113,13 @@ export const createStubClient = ( getAlias: sinon.spy(async ({ index, name }) => { if (index && existingIndices.indexOf(index) >= 0) { const result = indexAlias(aliases, index); - return { [index]: { aliases: result ? { [result]: {} } : {} } }; + return { body: { [index]: { aliases: result ? { [result]: {} } : {} } } }; } if (name && aliases[name]) { - return { [aliases[name]]: { aliases: { [name]: {} } } }; + return { body: { [aliases[name]]: { aliases: { [name]: {} } } } }; } - - return { status: 404 }; + return { statusCode: 404 }; }), updateAliases: sinon.spy(async ({ body }) => { body.actions.forEach( diff --git a/packages/osd-opensearch-archiver/src/opensearch_archiver.ts b/packages/osd-opensearch-archiver/src/opensearch_archiver.ts index 9e6a1246b184..bb831b05c0b0 100644 --- a/packages/osd-opensearch-archiver/src/opensearch_archiver.ts +++ b/packages/osd-opensearch-archiver/src/opensearch_archiver.ts @@ -28,7 +28,7 @@ * under the License. */ -import { Client } from 'elasticsearch'; +import { Client } from '@opensearch-project/opensearch'; import { ToolingLog, OsdClient } from '@osd/dev-utils'; import { diff --git a/packages/osd-optimizer/package.json b/packages/osd-optimizer/package.json index 27047c7b4ef5..aa9fae9b0d9f 100644 --- a/packages/osd-optimizer/package.json +++ b/packages/osd-optimizer/package.json @@ -33,7 +33,6 @@ "pirates": "^4.0.1", "postcss": "^8.4.5", "rxjs": "^6.5.5", - "node-sass": "^8.0.0", "source-map-support": "^0.5.19", "terser-webpack-plugin": "^2.1.2", "tinymath": "1.2.1", @@ -49,12 +48,14 @@ "@types/watchpack": "^1.1.6", "@types/webpack": "^4.41.31", "babel-loader": "^8.2.3", + "comment-stripper": "^0.0.4", "css-loader": "^5.2.7", "file-loader": "^6.2.0", "loader-utils": "^2.0.4", + "node-sass": "npm:@amoo-miki/node-sass@9.0.0-libsass-3.6.5", "postcss-loader": "^4.2.0", "raw-loader": "^4.0.2", - "sass-loader": "^10.4.1", + "sass-loader": "npm:@amoo-miki/sass-loader@10.4.1-node-sass-9.0.0-libsass-3.6.5", "style-loader": "^1.1.3", "url-loader": "^2.2.0", "val-loader": "^2.1.2", diff --git a/packages/osd-optimizer/postcss.config.js b/packages/osd-optimizer/postcss.config.js index 5b8b2e731989..2b1e3a8694ed 100644 --- a/packages/osd-optimizer/postcss.config.js +++ b/packages/osd-optimizer/postcss.config.js @@ -29,5 +29,7 @@ */ module.exports = { - plugins: [require('autoprefixer')()], + plugins: [ + /*require('autoprefixer')()*/ + ], }; diff --git a/packages/osd-optimizer/src/common/theme_tags.test.ts b/packages/osd-optimizer/src/common/theme_tags.test.ts index 2b34dee08628..791734e9cfb6 100644 --- a/packages/osd-optimizer/src/common/theme_tags.test.ts +++ b/packages/osd-optimizer/src/common/theme_tags.test.ts @@ -35,6 +35,8 @@ it('returns default tags when passed undefined', () => { Array [ "v7dark", "v7light", + "v8dark", + "v8light", ] `); }); diff --git a/packages/osd-optimizer/src/common/theme_tags.ts b/packages/osd-optimizer/src/common/theme_tags.ts index 3e62228ddaf9..8170c6bcab69 100644 --- a/packages/osd-optimizer/src/common/theme_tags.ts +++ b/packages/osd-optimizer/src/common/theme_tags.ts @@ -39,7 +39,7 @@ const isArrayOfStrings = (input: unknown): input is string[] => export type ThemeTags = readonly ThemeTag[]; export type ThemeTag = 'v7light' | 'v7dark' | 'v8light' | 'v8dark'; -export const DEFAULT_THEMES = tags('v7light', 'v7dark'); +export const DEFAULT_THEMES = tags('v7light', 'v7dark', 'v8light', 'v8dark'); export const ALL_THEMES = tags('v7light', 'v7dark', 'v8light', 'v8dark'); export function parseThemeTags(input?: any): ThemeTags { 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 63b7e44fea07..b08793cdae2f 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 @@ -69,6 +69,8 @@ OptimizerConfig { "themeTags": Array [ "v7dark", "v7light", + "v8dark", + "v8light", ], "watch": false, } @@ -78,4 +80,4 @@ exports[`prepares assets for distribution: bar bundle 1`] = `"(function(modules) exports[`prepares assets for distribution: foo async bundle 1`] = `"(window[\\"foo_bundle_jsonpfunction\\"]=window[\\"foo_bundle_jsonpfunction\\"]||[]).push([[1],{3:function(module,__webpack_exports__,__webpack_require__){\\"use strict\\";__webpack_require__.r(__webpack_exports__);__webpack_require__.d(__webpack_exports__,\\"foo\\",(function(){return foo}));function foo(){}}}]);"`; -exports[`prepares assets for distribution: foo bundle 1`] = `"(function(modules){function webpackJsonpCallback(data){var chunkIds=data[0];var moreModules=data[1];var moduleId,chunkId,i=0,resolves=[];for(;i { bar.cache.refresh(); expect(bar.cache.getModuleCount()).toBe( // code + styles + style/css-loader runtimes + public path updater - 17 + 25 ); expect(bar.cache.getReferencedFiles()?.map(absolutePathSerializer.serialize).sort()) @@ -193,6 +193,8 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { "/packages/osd-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/lib.ts", "/packages/osd-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v7dark.scss", "/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/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 b01228a09574..5ca5c76a566f 100644 --- a/packages/osd-optimizer/src/optimizer/cache_keys.test.ts +++ b/packages/osd-optimizer/src/optimizer/cache_keys.test.ts @@ -101,6 +101,8 @@ describe('getOptimizerCacheKey()', () => { "themeTags": Array [ "v7dark", "v7light", + "v8dark", + "v8light", ], }, } diff --git a/packages/osd-optimizer/src/worker/webpack.config.ts b/packages/osd-optimizer/src/worker/webpack.config.ts index f5272c207548..d11b14aaaee5 100644 --- a/packages/osd-optimizer/src/worker/webpack.config.ts +++ b/packages/osd-optimizer/src/worker/webpack.config.ts @@ -137,6 +137,12 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: sourceMap: !worker.dist, }, }, + { + loader: 'comment-stripper', + options: { + language: 'css', + }, + }, ], }, { @@ -164,6 +170,12 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: }, }, }, + { + loader: 'comment-stripper', + options: { + language: 'css', + }, + }, { loader: 'sass-loader', options: { diff --git a/packages/osd-pm/dist/index.js b/packages/osd-pm/dist/index.js index e43a9bfe407e..3e536751f711 100644 --- a/packages/osd-pm/dist/index.js +++ b/packages/osd-pm/dist/index.js @@ -134,15 +134,15 @@ Object.defineProperty(exports, "run", { var _cli = __webpack_require__(1); -var _production = __webpack_require__(515); +var _production = __webpack_require__(516); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); -var _project = __webpack_require__(164); +var _project = __webpack_require__(165); -var _workspaces = __webpack_require__(281); +var _workspaces = __webpack_require__(282); -var _config = __webpack_require__(282); +var _config = __webpack_require__(283); /***/ }), /* 1 */ @@ -166,9 +166,9 @@ var _tooling_log = __webpack_require__(5); var _commands = __webpack_require__(128); -var _run = __webpack_require__(510); +var _run = __webpack_require__(511); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -783,245 +783,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; +} /***/ }), @@ -1701,224 +1701,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; +} /***/ }), @@ -8322,158 +8322,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] +}; /***/ }), @@ -9062,11 +9062,11 @@ exports.commands = void 0; var _bootstrap = __webpack_require__(129); -var _clean = __webpack_require__(296); +var _clean = __webpack_require__(297); -var _run = __webpack_require__(409); +var _run = __webpack_require__(410); -var _watch = __webpack_require__(410); +var _watch = __webpack_require__(411); /* * SPDX-License-Identifier: Apache-2.0 @@ -9119,19 +9119,19 @@ exports.BootstrapCommand = void 0; var _link_project_executables = __webpack_require__(130); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); -var _parallelize = __webpack_require__(145); +var _parallelize = __webpack_require__(146); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); -var _project_checksums = __webpack_require__(283); +var _project_checksums = __webpack_require__(284); -var _bootstrap_cache_file = __webpack_require__(287); +var _bootstrap_cache_file = __webpack_require__(294); -var _yarn_lock = __webpack_require__(285); +var _yarn_lock = __webpack_require__(286); -var _validate_dependencies = __webpack_require__(288); +var _validate_dependencies = __webpack_require__(295); /* * SPDX-License-Identifier: Apache-2.0 @@ -9262,7 +9262,7 @@ var _path = __webpack_require__(4); var _fs = __webpack_require__(131); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); /* * SPDX-License-Identifier: Apache-2.0 @@ -9344,18 +9344,42 @@ async function linkProjectExecutables(projectsByName, projectGraph) { Object.defineProperty(exports, "__esModule", { value: true }); -exports.copyDirectory = exports.chmod = void 0; +Object.defineProperty(exports, "chmod", { + enumerable: true, + get: function () { + return _promises.chmod; + } +}); +exports.copyDirectory = void 0; exports.createSymlink = createSymlink; exports.isDirectory = isDirectory; exports.isFile = isFile; exports.isSymlink = isSymlink; -exports.writeFile = exports.unlink = exports.readFile = exports.mkdirp = void 0; +exports.mkdirp = void 0; +Object.defineProperty(exports, "readFile", { + enumerable: true, + get: function () { + return _promises.readFile; + } +}); +Object.defineProperty(exports, "unlink", { + enumerable: true, + get: function () { + return _promises.unlink; + } +}); +Object.defineProperty(exports, "writeFile", { + enumerable: true, + get: function () { + return _promises.writeFile; + } +}); var _cmdShim = _interopRequireDefault(__webpack_require__(132)); -var _fs = _interopRequireDefault(__webpack_require__(134)); +var _promises = __webpack_require__(143); -var _ncp = __webpack_require__(143); +var _ncp = __webpack_require__(144); var _path = __webpack_require__(4); @@ -9392,30 +9416,19 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * specific language governing permissions and limitations * under the License. */ -const lstat = (0, _util.promisify)(_fs.default.lstat); -const readFile = (0, _util.promisify)(_fs.default.readFile); -exports.readFile = readFile; -const writeFile = (0, _util.promisify)(_fs.default.writeFile); -exports.writeFile = writeFile; -const symlink = (0, _util.promisify)(_fs.default.symlink); -const chmod = (0, _util.promisify)(_fs.default.chmod); -exports.chmod = chmod; const cmdShim = (0, _util.promisify)(_cmdShim.default); -const mkdir = (0, _util.promisify)(_fs.default.mkdir); -const mkdirp = async path => await mkdir(path, { +const mkdirp = async path => await (0, _promises.mkdir)(path, { recursive: true }); exports.mkdirp = mkdirp; -const unlink = (0, _util.promisify)(_fs.default.unlink); -exports.unlink = unlink; const copyDirectory = (0, _util.promisify)(_ncp.ncp); exports.copyDirectory = copyDirectory; async function statTest(path, block) { try { - return block(await lstat(path)); + return block(await (0, _promises.lstat)(path)); } catch (e) { if (e.code === 'ENOENT') { return false; @@ -9480,14 +9493,14 @@ async function createSymlink(src, dest, type) { async function forceCreate(src, dest, type) { try { // If something exists at `dest` we need to remove it first. - await unlink(dest); + await (0, _promises.unlink)(dest); } catch (error) { if (error.code !== 'ENOENT') { throw error; } } - await symlink(src, dest, type); + await (0, _promises.symlink)(src, dest, type); } /***/ }), @@ -10848,62 +10861,68 @@ 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 +} + + +/***/ }), +/* 143 */ +/***/ (function(module, exports) { +module.exports = require("fs/promises"); /***/ }), -/* 143 */ +/* 144 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(134), @@ -11170,7 +11189,7 @@ function ncp (source, dest, options, callback) { /***/ }), -/* 144 */ +/* 145 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -11220,7 +11239,7 @@ const log = new Log(); exports.log = log; /***/ }), -/* 145 */ +/* 146 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -11303,7 +11322,7 @@ async function parallelize(items, fn, concurrency = 4) { } /***/ }), -/* 146 */ +/* 147 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -11317,17 +11336,17 @@ exports.getProjects = getProjects; exports.includeTransitiveProjects = includeTransitiveProjects; exports.topologicallyBatchProjects = topologicallyBatchProjects; -var _glob = _interopRequireDefault(__webpack_require__(147)); +var _glob = _interopRequireDefault(__webpack_require__(148)); var _path = _interopRequireDefault(__webpack_require__(4)); var _util = __webpack_require__(112); -var _errors = __webpack_require__(163); +var _errors = __webpack_require__(164); -var _project = __webpack_require__(164); +var _project = __webpack_require__(165); -var _workspaces = __webpack_require__(281); +var _workspaces = __webpack_require__(282); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -11538,7 +11557,7 @@ function includeTransitiveProjects(subsetOfProjects, allProjects, { } /***/ }), -/* 147 */ +/* 148 */ /***/ (function(module, exports, __webpack_require__) { // Approach: @@ -11583,24 +11602,24 @@ function includeTransitiveProjects(subsetOfProjects, allProjects, { module.exports = glob -var rp = __webpack_require__(148) -var minimatch = __webpack_require__(150) +var rp = __webpack_require__(149) +var minimatch = __webpack_require__(151) var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(154) -var EE = __webpack_require__(156).EventEmitter +var inherits = __webpack_require__(155) +var EE = __webpack_require__(157).EventEmitter var path = __webpack_require__(4) var assert = __webpack_require__(140) -var isAbsolute = __webpack_require__(157) -var globSync = __webpack_require__(158) -var common = __webpack_require__(159) +var isAbsolute = __webpack_require__(158) +var globSync = __webpack_require__(159) +var common = __webpack_require__(160) var setopts = common.setopts var ownProp = common.ownProp -var inflight = __webpack_require__(160) +var inflight = __webpack_require__(161) var util = __webpack_require__(112) var childrenIgnored = common.childrenIgnored var isIgnored = common.isIgnored -var once = __webpack_require__(162) +var once = __webpack_require__(163) function glob (pattern, options, cb) { if (typeof options === 'function') cb = options, options = {} @@ -12331,7 +12350,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) { /***/ }), -/* 148 */ +/* 149 */ /***/ (function(module, exports, __webpack_require__) { module.exports = realpath @@ -12347,7 +12366,7 @@ var origRealpathSync = fs.realpathSync var version = process.version var ok = /^v[0-5]\./.test(version) -var old = __webpack_require__(149) +var old = __webpack_require__(150) function newError (er) { return er && er.syscall === 'realpath' && ( @@ -12403,7 +12422,7 @@ function unmonkeypatch () { /***/ }), -/* 149 */ +/* 150 */ /***/ (function(module, exports, __webpack_require__) { // Copyright Joyent, Inc. and other Node contributors. @@ -12712,7 +12731,7 @@ exports.realpath = function realpath(p, cache, cb) { /***/ }), -/* 150 */ +/* 151 */ /***/ (function(module, exports, __webpack_require__) { module.exports = minimatch @@ -12724,7 +12743,7 @@ var path = (function () { try { return __webpack_require__(4) } catch (e) {}}()) minimatch.sep = path.sep var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} -var expand = __webpack_require__(151) +var expand = __webpack_require__(152) var plTypes = { '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, @@ -13665,11 +13684,11 @@ function regExpEscape (s) { /***/ }), -/* 151 */ +/* 152 */ /***/ (function(module, exports, __webpack_require__) { -var concatMap = __webpack_require__(152); -var balanced = __webpack_require__(153); +var concatMap = __webpack_require__(153); +var balanced = __webpack_require__(154); module.exports = expandTop; @@ -13872,7 +13891,7 @@ function expand(str, isTop) { /***/ }), -/* 152 */ +/* 153 */ /***/ (function(module, exports) { module.exports = function (xs, fn) { @@ -13891,7 +13910,7 @@ var isArray = Array.isArray || function (xs) { /***/ }), -/* 153 */ +/* 154 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -13960,7 +13979,7 @@ function range(a, b, str) { /***/ }), -/* 154 */ +/* 155 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -13970,12 +13989,12 @@ try { module.exports = util.inherits; } catch (e) { /* istanbul ignore next */ - module.exports = __webpack_require__(155); + module.exports = __webpack_require__(156); } /***/ }), -/* 155 */ +/* 156 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -14008,13 +14027,13 @@ if (typeof Object.create === 'function') { /***/ }), -/* 156 */ +/* 157 */ /***/ (function(module, exports) { module.exports = require("events"); /***/ }), -/* 157 */ +/* 158 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -14041,21 +14060,21 @@ module.exports.win32 = win32; /***/ }), -/* 158 */ +/* 159 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync globSync.GlobSync = GlobSync -var rp = __webpack_require__(148) -var minimatch = __webpack_require__(150) +var rp = __webpack_require__(149) +var minimatch = __webpack_require__(151) var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(147).Glob +var Glob = __webpack_require__(148).Glob var util = __webpack_require__(112) var path = __webpack_require__(4) var assert = __webpack_require__(140) -var isAbsolute = __webpack_require__(157) -var common = __webpack_require__(159) +var isAbsolute = __webpack_require__(158) +var common = __webpack_require__(160) var setopts = common.setopts var ownProp = common.ownProp var childrenIgnored = common.childrenIgnored @@ -14530,7 +14549,7 @@ GlobSync.prototype._makeAbs = function (f) { /***/ }), -/* 159 */ +/* 160 */ /***/ (function(module, exports, __webpack_require__) { exports.setopts = setopts @@ -14547,8 +14566,8 @@ function ownProp (obj, field) { var fs = __webpack_require__(134) var path = __webpack_require__(4) -var minimatch = __webpack_require__(150) -var isAbsolute = __webpack_require__(157) +var minimatch = __webpack_require__(151) +var isAbsolute = __webpack_require__(158) var Minimatch = minimatch.Minimatch function alphasort (a, b) { @@ -14772,12 +14791,12 @@ function childrenIgnored (self, path) { /***/ }), -/* 160 */ +/* 161 */ /***/ (function(module, exports, __webpack_require__) { -var wrappy = __webpack_require__(161) +var wrappy = __webpack_require__(162) var reqs = Object.create(null) -var once = __webpack_require__(162) +var once = __webpack_require__(163) module.exports = wrappy(inflight) @@ -14832,7 +14851,7 @@ function slice (args) { /***/ }), -/* 161 */ +/* 162 */ /***/ (function(module, exports) { // Returns a wrapper function that returns a wrapped callback @@ -14871,10 +14890,10 @@ function wrappy (fn, cb) { /***/ }), -/* 162 */ +/* 163 */ /***/ (function(module, exports, __webpack_require__) { -var wrappy = __webpack_require__(161) +var wrappy = __webpack_require__(162) module.exports = wrappy(once) module.exports.strict = wrappy(onceStrict) @@ -14919,7 +14938,7 @@ function onceStrict (fn) { /***/ }), -/* 163 */ +/* 164 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -14970,7 +14989,7 @@ class CliError extends Error { exports.CliError = CliError; /***/ }), -/* 164 */ +/* 165 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -14987,13 +15006,13 @@ var _path = _interopRequireDefault(__webpack_require__(4)); var _util = __webpack_require__(112); -var _errors = __webpack_require__(163); +var _errors = __webpack_require__(164); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); -var _package_json = __webpack_require__(165); +var _package_json = __webpack_require__(166); -var _scripts = __webpack_require__(235); +var _scripts = __webpack_require__(236); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -15221,7 +15240,7 @@ function normalizePath(path) { } /***/ }), -/* 165 */ +/* 166 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15234,9 +15253,9 @@ exports.isLinkDependency = void 0; exports.readPackageJson = readPackageJson; exports.writePackageJson = writePackageJson; -var _readPkg = _interopRequireDefault(__webpack_require__(166)); +var _readPkg = _interopRequireDefault(__webpack_require__(167)); -var _writePkg = _interopRequireDefault(__webpack_require__(223)); +var _writePkg = _interopRequireDefault(__webpack_require__(224)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -15285,7 +15304,7 @@ const isLinkDependency = depVersion => depVersion.startsWith('link:'); exports.isLinkDependency = isLinkDependency; /***/ }), -/* 166 */ +/* 167 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15293,7 +15312,7 @@ exports.isLinkDependency = isLinkDependency; const {promisify} = __webpack_require__(112); const fs = __webpack_require__(134); const path = __webpack_require__(4); -const parseJson = __webpack_require__(167); +const parseJson = __webpack_require__(168); const readFileAsync = promisify(fs.readFile); @@ -15308,7 +15327,7 @@ module.exports = async options => { const json = parseJson(await readFileAsync(filePath, 'utf8')); if (options.normalize) { - __webpack_require__(188)(json); + __webpack_require__(189)(json); } return json; @@ -15325,7 +15344,7 @@ module.exports.sync = options => { const json = parseJson(fs.readFileSync(filePath, 'utf8')); if (options.normalize) { - __webpack_require__(188)(json); + __webpack_require__(189)(json); } return json; @@ -15333,15 +15352,15 @@ module.exports.sync = options => { /***/ }), -/* 167 */ +/* 168 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const errorEx = __webpack_require__(168); -const fallback = __webpack_require__(170); -const {default: LinesAndColumns} = __webpack_require__(171); -const {codeFrameColumns} = __webpack_require__(172); +const errorEx = __webpack_require__(169); +const fallback = __webpack_require__(171); +const {default: LinesAndColumns} = __webpack_require__(172); +const {codeFrameColumns} = __webpack_require__(173); const JSONError = errorEx('JSONError', { fileName: errorEx.append('in %s'), @@ -15394,14 +15413,14 @@ module.exports = parseJson; /***/ }), -/* 168 */ +/* 169 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var isArrayish = __webpack_require__(169); +var isArrayish = __webpack_require__(170); var errorEx = function errorEx(name, properties) { if (!name || name.constructor !== String) { @@ -15542,7 +15561,7 @@ module.exports = errorEx; /***/ }), -/* 169 */ +/* 170 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15559,7 +15578,7 @@ module.exports = function isArrayish(obj) { /***/ }), -/* 170 */ +/* 171 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15687,7 +15706,7 @@ parseJson.noExceptions = (txt, reviver) => { /***/ }), -/* 171 */ +/* 172 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15756,7 +15775,7 @@ exports["default"] = LinesAndColumns; /***/ }), -/* 172 */ +/* 173 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15768,7 +15787,7 @@ Object.defineProperty(exports, "__esModule", { exports.codeFrameColumns = codeFrameColumns; exports.default = _default; -var _highlight = __webpack_require__(173); +var _highlight = __webpack_require__(174); let deprecationWarningShown = false; @@ -15925,7 +15944,7 @@ function _default(rawLines, lineNumber, colNumber, opts = {}) { } /***/ }), -/* 173 */ +/* 174 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -15938,11 +15957,11 @@ exports.default = highlight; exports.getChalk = getChalk; exports.shouldHighlight = shouldHighlight; -var _jsTokens = __webpack_require__(174); +var _jsTokens = __webpack_require__(175); -var _helperValidatorIdentifier = __webpack_require__(175); +var _helperValidatorIdentifier = __webpack_require__(176); -var _chalk = __webpack_require__(178); +var _chalk = __webpack_require__(179); const sometimesKeywords = new Set(["as", "async", "from", "get", "of", "set"]); @@ -16047,7 +16066,7 @@ function highlight(code, options = {}) { } /***/ }), -/* 174 */ +/* 175 */ /***/ (function(module, exports) { // Copyright 2014, 2015, 2016, 2017, 2018 Simon Lydell @@ -16076,7 +16095,7 @@ exports.matchToToken = function(match) { /***/ }), -/* 175 */ +/* 176 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16134,12 +16153,12 @@ Object.defineProperty(exports, "isStrictReservedWord", { } }); -var _identifier = __webpack_require__(176); +var _identifier = __webpack_require__(177); -var _keyword = __webpack_require__(177); +var _keyword = __webpack_require__(178); /***/ }), -/* 176 */ +/* 177 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16229,7 +16248,7 @@ function isIdentifierName(name) { } /***/ }), -/* 177 */ +/* 178 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16273,16 +16292,16 @@ function isKeyword(word) { } /***/ }), -/* 178 */ +/* 179 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const escapeStringRegexp = __webpack_require__(179); -const ansiStyles = __webpack_require__(180); -const stdoutColor = __webpack_require__(185).stdout; +const escapeStringRegexp = __webpack_require__(180); +const ansiStyles = __webpack_require__(181); +const stdoutColor = __webpack_require__(186).stdout; -const template = __webpack_require__(187); +const template = __webpack_require__(188); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -16508,7 +16527,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 179 */ +/* 180 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -16526,12 +16545,12 @@ module.exports = function (str) { /***/ }), -/* 180 */ +/* 181 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* WEBPACK VAR INJECTION */(function(module) { -const colorConvert = __webpack_require__(181); +const colorConvert = __webpack_require__(182); const wrapAnsi16 = (fn, offset) => function () { const code = fn.apply(colorConvert, arguments); @@ -16699,11 +16718,11 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(115)(module))) /***/ }), -/* 181 */ +/* 182 */ /***/ (function(module, exports, __webpack_require__) { -var conversions = __webpack_require__(182); -var route = __webpack_require__(184); +var conversions = __webpack_require__(183); +var route = __webpack_require__(185); var convert = {}; @@ -16783,11 +16802,11 @@ module.exports = convert; /***/ }), -/* 182 */ +/* 183 */ /***/ (function(module, exports, __webpack_require__) { /* MIT license */ -var cssKeywords = __webpack_require__(183); +var cssKeywords = __webpack_require__(184); // NOTE: conversions should only return primitive values (i.e. arrays, or // values that give correct `typeof` results). @@ -17657,169 +17676,169 @@ convert.rgb.gray = function (rgb) { /***/ }), -/* 183 */ +/* 184 */ /***/ (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] +}; /***/ }), -/* 184 */ +/* 185 */ /***/ (function(module, exports, __webpack_require__) { -var conversions = __webpack_require__(182); +var conversions = __webpack_require__(183); /* this function routes a model to all other models. @@ -17919,13 +17938,13 @@ module.exports = function (fromModel) { /***/ }), -/* 185 */ +/* 186 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const os = __webpack_require__(121); -const hasFlag = __webpack_require__(186); +const hasFlag = __webpack_require__(187); const env = process.env; @@ -18057,7 +18076,7 @@ module.exports = { /***/ }), -/* 186 */ +/* 187 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18072,7 +18091,7 @@ module.exports = (flag, argv) => { /***/ }), -/* 187 */ +/* 188 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -18207,15 +18226,15 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 188 */ +/* 189 */ /***/ (function(module, exports, __webpack_require__) { module.exports = normalize -var fixer = __webpack_require__(189) +var fixer = __webpack_require__(190) normalize.fixer = fixer -var makeWarning = __webpack_require__(221) +var makeWarning = __webpack_require__(222) var fieldsToFix = ['name','version','description','repository','modules','scripts' ,'files','bin','man','bugs','keywords','readme','homepage','license'] @@ -18252,17 +18271,17 @@ function ucFirst (string) { /***/ }), -/* 189 */ +/* 190 */ /***/ (function(module, exports, __webpack_require__) { -var semver = __webpack_require__(190) -var validateLicense = __webpack_require__(191); -var hostedGitInfo = __webpack_require__(199) -var isBuiltinModule = __webpack_require__(203).isCore +var semver = __webpack_require__(191) +var validateLicense = __webpack_require__(192); +var hostedGitInfo = __webpack_require__(200) +var isBuiltinModule = __webpack_require__(204).isCore var depTypes = ["dependencies","devDependencies","optionalDependencies"] -var extractDescription = __webpack_require__(219) -var url = __webpack_require__(200) -var typos = __webpack_require__(220) +var extractDescription = __webpack_require__(220) +var url = __webpack_require__(201) +var typos = __webpack_require__(221) var fixer = module.exports = { // default warning function @@ -18676,7 +18695,7 @@ function bugsTypos(bugs, warn) { /***/ }), -/* 190 */ +/* 191 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -20165,11 +20184,11 @@ function coerce (version) { /***/ }), -/* 191 */ +/* 192 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(192); -var correct = __webpack_require__(198); +var parse = __webpack_require__(193); +var correct = __webpack_require__(199); var genericWarning = ( 'license should be ' + @@ -20257,14 +20276,14 @@ module.exports = function(argument) { /***/ }), -/* 192 */ +/* 193 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var scan = __webpack_require__(193) -var parse = __webpack_require__(197) +var scan = __webpack_require__(194) +var parse = __webpack_require__(198) module.exports = function (source) { return parse(scan(source)) @@ -20272,16 +20291,16 @@ module.exports = function (source) { /***/ }), -/* 193 */ +/* 194 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var licenses = [] - .concat(__webpack_require__(194)) .concat(__webpack_require__(195)) -var exceptions = __webpack_require__(196) + .concat(__webpack_require__(196)) +var exceptions = __webpack_require__(197) module.exports = function (source) { var index = 0 @@ -20410,25 +20429,25 @@ module.exports = function (source) { /***/ }), -/* 194 */ +/* 195 */ /***/ (function(module) { module.exports = JSON.parse("[\"0BSD\",\"AAL\",\"ADSL\",\"AFL-1.1\",\"AFL-1.2\",\"AFL-2.0\",\"AFL-2.1\",\"AFL-3.0\",\"AGPL-1.0-only\",\"AGPL-1.0-or-later\",\"AGPL-3.0-only\",\"AGPL-3.0-or-later\",\"AMDPLPA\",\"AML\",\"AMPAS\",\"ANTLR-PD\",\"ANTLR-PD-fallback\",\"APAFML\",\"APL-1.0\",\"APSL-1.0\",\"APSL-1.1\",\"APSL-1.2\",\"APSL-2.0\",\"Abstyles\",\"Adobe-2006\",\"Adobe-Glyph\",\"Afmparse\",\"Aladdin\",\"Apache-1.0\",\"Apache-1.1\",\"Apache-2.0\",\"Artistic-1.0\",\"Artistic-1.0-Perl\",\"Artistic-1.0-cl8\",\"Artistic-2.0\",\"BSD-1-Clause\",\"BSD-2-Clause\",\"BSD-2-Clause-Patent\",\"BSD-2-Clause-Views\",\"BSD-3-Clause\",\"BSD-3-Clause-Attribution\",\"BSD-3-Clause-Clear\",\"BSD-3-Clause-LBNL\",\"BSD-3-Clause-Modification\",\"BSD-3-Clause-No-Military-License\",\"BSD-3-Clause-No-Nuclear-License\",\"BSD-3-Clause-No-Nuclear-License-2014\",\"BSD-3-Clause-No-Nuclear-Warranty\",\"BSD-3-Clause-Open-MPI\",\"BSD-4-Clause\",\"BSD-4-Clause-Shortened\",\"BSD-4-Clause-UC\",\"BSD-Protection\",\"BSD-Source-Code\",\"BSL-1.0\",\"BUSL-1.1\",\"Bahyph\",\"Barr\",\"Beerware\",\"BitTorrent-1.0\",\"BitTorrent-1.1\",\"BlueOak-1.0.0\",\"Borceux\",\"C-UDA-1.0\",\"CAL-1.0\",\"CAL-1.0-Combined-Work-Exception\",\"CATOSL-1.1\",\"CC-BY-1.0\",\"CC-BY-2.0\",\"CC-BY-2.5\",\"CC-BY-2.5-AU\",\"CC-BY-3.0\",\"CC-BY-3.0-AT\",\"CC-BY-3.0-DE\",\"CC-BY-3.0-NL\",\"CC-BY-3.0-US\",\"CC-BY-4.0\",\"CC-BY-NC-1.0\",\"CC-BY-NC-2.0\",\"CC-BY-NC-2.5\",\"CC-BY-NC-3.0\",\"CC-BY-NC-3.0-DE\",\"CC-BY-NC-4.0\",\"CC-BY-NC-ND-1.0\",\"CC-BY-NC-ND-2.0\",\"CC-BY-NC-ND-2.5\",\"CC-BY-NC-ND-3.0\",\"CC-BY-NC-ND-3.0-DE\",\"CC-BY-NC-ND-3.0-IGO\",\"CC-BY-NC-ND-4.0\",\"CC-BY-NC-SA-1.0\",\"CC-BY-NC-SA-2.0\",\"CC-BY-NC-SA-2.0-FR\",\"CC-BY-NC-SA-2.0-UK\",\"CC-BY-NC-SA-2.5\",\"CC-BY-NC-SA-3.0\",\"CC-BY-NC-SA-3.0-DE\",\"CC-BY-NC-SA-3.0-IGO\",\"CC-BY-NC-SA-4.0\",\"CC-BY-ND-1.0\",\"CC-BY-ND-2.0\",\"CC-BY-ND-2.5\",\"CC-BY-ND-3.0\",\"CC-BY-ND-3.0-DE\",\"CC-BY-ND-4.0\",\"CC-BY-SA-1.0\",\"CC-BY-SA-2.0\",\"CC-BY-SA-2.0-UK\",\"CC-BY-SA-2.1-JP\",\"CC-BY-SA-2.5\",\"CC-BY-SA-3.0\",\"CC-BY-SA-3.0-AT\",\"CC-BY-SA-3.0-DE\",\"CC-BY-SA-4.0\",\"CC-PDDC\",\"CC0-1.0\",\"CDDL-1.0\",\"CDDL-1.1\",\"CDL-1.0\",\"CDLA-Permissive-1.0\",\"CDLA-Permissive-2.0\",\"CDLA-Sharing-1.0\",\"CECILL-1.0\",\"CECILL-1.1\",\"CECILL-2.0\",\"CECILL-2.1\",\"CECILL-B\",\"CECILL-C\",\"CERN-OHL-1.1\",\"CERN-OHL-1.2\",\"CERN-OHL-P-2.0\",\"CERN-OHL-S-2.0\",\"CERN-OHL-W-2.0\",\"CNRI-Jython\",\"CNRI-Python\",\"CNRI-Python-GPL-Compatible\",\"COIL-1.0\",\"CPAL-1.0\",\"CPL-1.0\",\"CPOL-1.02\",\"CUA-OPL-1.0\",\"Caldera\",\"ClArtistic\",\"Community-Spec-1.0\",\"Condor-1.1\",\"Crossword\",\"CrystalStacker\",\"Cube\",\"D-FSL-1.0\",\"DOC\",\"DRL-1.0\",\"DSDP\",\"Dotseqn\",\"ECL-1.0\",\"ECL-2.0\",\"EFL-1.0\",\"EFL-2.0\",\"EPICS\",\"EPL-1.0\",\"EPL-2.0\",\"EUDatagrid\",\"EUPL-1.0\",\"EUPL-1.1\",\"EUPL-1.2\",\"Entessa\",\"ErlPL-1.1\",\"Eurosym\",\"FDK-AAC\",\"FSFAP\",\"FSFUL\",\"FSFULLR\",\"FTL\",\"Fair\",\"Frameworx-1.0\",\"FreeBSD-DOC\",\"FreeImage\",\"GD\",\"GFDL-1.1-invariants-only\",\"GFDL-1.1-invariants-or-later\",\"GFDL-1.1-no-invariants-only\",\"GFDL-1.1-no-invariants-or-later\",\"GFDL-1.1-only\",\"GFDL-1.1-or-later\",\"GFDL-1.2-invariants-only\",\"GFDL-1.2-invariants-or-later\",\"GFDL-1.2-no-invariants-only\",\"GFDL-1.2-no-invariants-or-later\",\"GFDL-1.2-only\",\"GFDL-1.2-or-later\",\"GFDL-1.3-invariants-only\",\"GFDL-1.3-invariants-or-later\",\"GFDL-1.3-no-invariants-only\",\"GFDL-1.3-no-invariants-or-later\",\"GFDL-1.3-only\",\"GFDL-1.3-or-later\",\"GL2PS\",\"GLWTPL\",\"GPL-1.0-only\",\"GPL-1.0-or-later\",\"GPL-2.0-only\",\"GPL-2.0-or-later\",\"GPL-3.0-only\",\"GPL-3.0-or-later\",\"Giftware\",\"Glide\",\"Glulxe\",\"HPND\",\"HPND-sell-variant\",\"HTMLTIDY\",\"HaskellReport\",\"Hippocratic-2.1\",\"IBM-pibs\",\"ICU\",\"IJG\",\"IPA\",\"IPL-1.0\",\"ISC\",\"ImageMagick\",\"Imlib2\",\"Info-ZIP\",\"Intel\",\"Intel-ACPI\",\"Interbase-1.0\",\"JPNIC\",\"JSON\",\"JasPer-2.0\",\"LAL-1.2\",\"LAL-1.3\",\"LGPL-2.0-only\",\"LGPL-2.0-or-later\",\"LGPL-2.1-only\",\"LGPL-2.1-or-later\",\"LGPL-3.0-only\",\"LGPL-3.0-or-later\",\"LGPLLR\",\"LPL-1.0\",\"LPL-1.02\",\"LPPL-1.0\",\"LPPL-1.1\",\"LPPL-1.2\",\"LPPL-1.3a\",\"LPPL-1.3c\",\"Latex2e\",\"Leptonica\",\"LiLiQ-P-1.1\",\"LiLiQ-R-1.1\",\"LiLiQ-Rplus-1.1\",\"Libpng\",\"Linux-OpenIB\",\"Linux-man-pages-copyleft\",\"MIT\",\"MIT-0\",\"MIT-CMU\",\"MIT-Modern-Variant\",\"MIT-advertising\",\"MIT-enna\",\"MIT-feh\",\"MIT-open-group\",\"MITNFA\",\"MPL-1.0\",\"MPL-1.1\",\"MPL-2.0\",\"MPL-2.0-no-copyleft-exception\",\"MS-PL\",\"MS-RL\",\"MTLL\",\"MakeIndex\",\"MirOS\",\"Motosoto\",\"MulanPSL-1.0\",\"MulanPSL-2.0\",\"Multics\",\"Mup\",\"NAIST-2003\",\"NASA-1.3\",\"NBPL-1.0\",\"NCGL-UK-2.0\",\"NCSA\",\"NGPL\",\"NIST-PD\",\"NIST-PD-fallback\",\"NLOD-1.0\",\"NLOD-2.0\",\"NLPL\",\"NOSL\",\"NPL-1.0\",\"NPL-1.1\",\"NPOSL-3.0\",\"NRL\",\"NTP\",\"NTP-0\",\"Naumen\",\"Net-SNMP\",\"NetCDF\",\"Newsletr\",\"Nokia\",\"Noweb\",\"O-UDA-1.0\",\"OCCT-PL\",\"OCLC-2.0\",\"ODC-By-1.0\",\"ODbL-1.0\",\"OFL-1.0\",\"OFL-1.0-RFN\",\"OFL-1.0-no-RFN\",\"OFL-1.1\",\"OFL-1.1-RFN\",\"OFL-1.1-no-RFN\",\"OGC-1.0\",\"OGDL-Taiwan-1.0\",\"OGL-Canada-2.0\",\"OGL-UK-1.0\",\"OGL-UK-2.0\",\"OGL-UK-3.0\",\"OGTSL\",\"OLDAP-1.1\",\"OLDAP-1.2\",\"OLDAP-1.3\",\"OLDAP-1.4\",\"OLDAP-2.0\",\"OLDAP-2.0.1\",\"OLDAP-2.1\",\"OLDAP-2.2\",\"OLDAP-2.2.1\",\"OLDAP-2.2.2\",\"OLDAP-2.3\",\"OLDAP-2.4\",\"OLDAP-2.5\",\"OLDAP-2.6\",\"OLDAP-2.7\",\"OLDAP-2.8\",\"OML\",\"OPL-1.0\",\"OPUBL-1.0\",\"OSET-PL-2.1\",\"OSL-1.0\",\"OSL-1.1\",\"OSL-2.0\",\"OSL-2.1\",\"OSL-3.0\",\"OpenSSL\",\"PDDL-1.0\",\"PHP-3.0\",\"PHP-3.01\",\"PSF-2.0\",\"Parity-6.0.0\",\"Parity-7.0.0\",\"Plexus\",\"PolyForm-Noncommercial-1.0.0\",\"PolyForm-Small-Business-1.0.0\",\"PostgreSQL\",\"Python-2.0\",\"QPL-1.0\",\"Qhull\",\"RHeCos-1.1\",\"RPL-1.1\",\"RPL-1.5\",\"RPSL-1.0\",\"RSA-MD\",\"RSCPL\",\"Rdisc\",\"Ruby\",\"SAX-PD\",\"SCEA\",\"SGI-B-1.0\",\"SGI-B-1.1\",\"SGI-B-2.0\",\"SHL-0.5\",\"SHL-0.51\",\"SISSL\",\"SISSL-1.2\",\"SMLNJ\",\"SMPPL\",\"SNIA\",\"SPL-1.0\",\"SSH-OpenSSH\",\"SSH-short\",\"SSPL-1.0\",\"SWL\",\"Saxpath\",\"Sendmail\",\"Sendmail-8.23\",\"SimPL-2.0\",\"Sleepycat\",\"Spencer-86\",\"Spencer-94\",\"Spencer-99\",\"SugarCRM-1.1.3\",\"TAPR-OHL-1.0\",\"TCL\",\"TCP-wrappers\",\"TMate\",\"TORQUE-1.1\",\"TOSL\",\"TU-Berlin-1.0\",\"TU-Berlin-2.0\",\"UCL-1.0\",\"UPL-1.0\",\"Unicode-DFS-2015\",\"Unicode-DFS-2016\",\"Unicode-TOU\",\"Unlicense\",\"VOSTROM\",\"VSL-1.0\",\"Vim\",\"W3C\",\"W3C-19980720\",\"W3C-20150513\",\"WTFPL\",\"Watcom-1.0\",\"Wsuipa\",\"X11\",\"XFree86-1.1\",\"XSkat\",\"Xerox\",\"Xnet\",\"YPL-1.0\",\"YPL-1.1\",\"ZPL-1.1\",\"ZPL-2.0\",\"ZPL-2.1\",\"Zed\",\"Zend-2.0\",\"Zimbra-1.3\",\"Zimbra-1.4\",\"Zlib\",\"blessing\",\"bzip2-1.0.5\",\"bzip2-1.0.6\",\"copyleft-next-0.3.0\",\"copyleft-next-0.3.1\",\"curl\",\"diffmark\",\"dvipdfm\",\"eGenix\",\"etalab-2.0\",\"gSOAP-1.3b\",\"gnuplot\",\"iMatix\",\"libpng-2.0\",\"libselinux-1.0\",\"libtiff\",\"mpich2\",\"psfrag\",\"psutils\",\"xinetd\",\"xpp\",\"zlib-acknowledgement\"]"); /***/ }), -/* 195 */ +/* 196 */ /***/ (function(module) { module.exports = JSON.parse("[\"AGPL-1.0\",\"AGPL-3.0\",\"BSD-2-Clause-FreeBSD\",\"BSD-2-Clause-NetBSD\",\"GFDL-1.1\",\"GFDL-1.2\",\"GFDL-1.3\",\"GPL-1.0\",\"GPL-2.0\",\"GPL-2.0-with-GCC-exception\",\"GPL-2.0-with-autoconf-exception\",\"GPL-2.0-with-bison-exception\",\"GPL-2.0-with-classpath-exception\",\"GPL-2.0-with-font-exception\",\"GPL-3.0\",\"GPL-3.0-with-GCC-exception\",\"GPL-3.0-with-autoconf-exception\",\"LGPL-2.0\",\"LGPL-2.1\",\"LGPL-3.0\",\"Nunit\",\"StandardML-NJ\",\"eCos-2.0\",\"wxWindows\"]"); /***/ }), -/* 196 */ +/* 197 */ /***/ (function(module) { module.exports = JSON.parse("[\"389-exception\",\"Autoconf-exception-2.0\",\"Autoconf-exception-3.0\",\"Bison-exception-2.2\",\"Bootloader-exception\",\"Classpath-exception-2.0\",\"CLISP-exception-2.0\",\"DigiRule-FOSS-exception\",\"eCos-exception-2.0\",\"Fawkes-Runtime-exception\",\"FLTK-exception\",\"Font-exception-2.0\",\"freertos-exception-2.0\",\"GCC-exception-2.0\",\"GCC-exception-3.1\",\"gnu-javamail-exception\",\"GPL-3.0-linking-exception\",\"GPL-3.0-linking-source-exception\",\"GPL-CC-1.0\",\"i2p-gpl-java-exception\",\"Libtool-exception\",\"Linux-syscall-note\",\"LLVM-exception\",\"LZMA-exception\",\"mif-exception\",\"Nokia-Qt-exception-1.1\",\"OCaml-LGPL-linking-exception\",\"OCCT-exception-1.0\",\"OpenJDK-assembly-exception-1.0\",\"openvpn-openssl-exception\",\"PS-or-PDF-font-exception-20170817\",\"Qt-GPL-exception-1.0\",\"Qt-LGPL-exception-1.1\",\"Qwt-exception-1.0\",\"Swift-exception\",\"u-boot-exception-2.0\",\"Universal-FOSS-exception-1.0\",\"WxWindows-exception-3.1\"]"); /***/ }), -/* 197 */ +/* 198 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -20573,7 +20592,7 @@ module.exports = function (tokens) { /***/ }), -/* 198 */ +/* 199 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -20591,8 +20610,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -var parse = __webpack_require__(192) -var spdxLicenseIds = __webpack_require__(194) +var parse = __webpack_require__(193) +var spdxLicenseIds = __webpack_require__(195) function valid (string) { try { @@ -20943,14 +20962,14 @@ function upgradeGPLs (value) { /***/ }), -/* 199 */ +/* 200 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var url = __webpack_require__(200) -var gitHosts = __webpack_require__(201) -var GitHost = module.exports = __webpack_require__(202) +var url = __webpack_require__(201) +var gitHosts = __webpack_require__(202) +var GitHost = module.exports = __webpack_require__(203) var protocolToRepresentationMap = { 'git+ssh:': 'sshurl', @@ -21098,13 +21117,13 @@ function parseGitUrl (giturl) { /***/ }), -/* 200 */ +/* 201 */ /***/ (function(module, exports) { module.exports = require("url"); /***/ }), -/* 201 */ +/* 202 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -21190,12 +21209,12 @@ function formatHashFragment (fragment) { /***/ }), -/* 202 */ +/* 203 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var gitHosts = __webpack_require__(201) +var gitHosts = __webpack_require__(202) /* eslint-disable node/no-deprecated-api */ // copy-pasta util._extend from node's source, to avoid pulling @@ -21353,28 +21372,28 @@ GitHost.prototype.toString = function (opts) { /***/ }), -/* 203 */ +/* 204 */ /***/ (function(module, exports, __webpack_require__) { -var async = __webpack_require__(204); -async.core = __webpack_require__(215); -async.isCore = __webpack_require__(217); -async.sync = __webpack_require__(218); +var async = __webpack_require__(205); +async.core = __webpack_require__(216); +async.isCore = __webpack_require__(218); +async.sync = __webpack_require__(219); module.exports = async; /***/ }), -/* 204 */ +/* 205 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(134); -var getHomedir = __webpack_require__(205); +var getHomedir = __webpack_require__(206); var path = __webpack_require__(4); -var caller = __webpack_require__(206); -var nodeModulesPaths = __webpack_require__(207); -var normalizeOptions = __webpack_require__(209); -var isCore = __webpack_require__(210); +var caller = __webpack_require__(207); +var nodeModulesPaths = __webpack_require__(208); +var normalizeOptions = __webpack_require__(210); +var isCore = __webpack_require__(211); var realpathFS = process.platform !== 'win32' && fs.realpath && typeof fs.realpath.native === 'function' ? fs.realpath.native : fs.realpath; @@ -21700,7 +21719,7 @@ module.exports = function resolve(x, options, callback) { /***/ }), -/* 205 */ +/* 206 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -21731,7 +21750,7 @@ module.exports = os.homedir || function homedir() { /***/ }), -/* 206 */ +/* 207 */ /***/ (function(module, exports) { module.exports = function () { @@ -21745,11 +21764,11 @@ module.exports = function () { /***/ }), -/* 207 */ +/* 208 */ /***/ (function(module, exports, __webpack_require__) { var path = __webpack_require__(4); -var parse = path.parse || __webpack_require__(208); // eslint-disable-line global-require +var parse = path.parse || __webpack_require__(209); // eslint-disable-line global-require var getNodeModulesDirs = function getNodeModulesDirs(absoluteStart, modules) { var prefix = '/'; @@ -21793,7 +21812,7 @@ module.exports = function nodeModulesPaths(start, opts, request) { /***/ }), -/* 208 */ +/* 209 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -21875,7 +21894,7 @@ module.exports.win32 = win32.parse; /***/ }), -/* 209 */ +/* 210 */ /***/ (function(module, exports) { module.exports = function (x, opts) { @@ -21891,13 +21910,13 @@ module.exports = function (x, opts) { /***/ }), -/* 210 */ +/* 211 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var has = __webpack_require__(211); +var has = __webpack_require__(212); function specifierIncluded(current, specifier) { var nodeParts = current.split('.'); @@ -21959,7 +21978,7 @@ function versionIncluded(nodeVersion, specifierValue) { return matchesRange(current, specifierValue); } -var data = __webpack_require__(214); +var data = __webpack_require__(215); module.exports = function isCore(x, nodeVersion) { return has(data, x) && versionIncluded(nodeVersion, data[x]); @@ -21967,31 +21986,31 @@ module.exports = function isCore(x, nodeVersion) { /***/ }), -/* 211 */ +/* 212 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var bind = __webpack_require__(212); +var bind = __webpack_require__(213); module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty); /***/ }), -/* 212 */ +/* 213 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var implementation = __webpack_require__(213); +var implementation = __webpack_require__(214); module.exports = Function.prototype.bind || implementation; /***/ }), -/* 213 */ +/* 214 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -22050,13 +22069,13 @@ module.exports = function bind(that) { /***/ }), -/* 214 */ +/* 215 */ /***/ (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\"]}"); /***/ }), -/* 215 */ +/* 216 */ /***/ (function(module, exports, __webpack_require__) { var current = (process.versions && process.versions.node && process.versions.node.split('.')) || []; @@ -22102,7 +22121,7 @@ function versionIncluded(specifierValue) { return matchesRange(specifierValue); } -var data = __webpack_require__(216); +var data = __webpack_require__(217); var core = {}; for (var mod in data) { // eslint-disable-line no-restricted-syntax @@ -22114,16 +22133,16 @@ module.exports = core; /***/ }), -/* 216 */ +/* 217 */ /***/ (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\"],\"_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\":\">= 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\"]}"); /***/ }), -/* 217 */ +/* 218 */ /***/ (function(module, exports, __webpack_require__) { -var isCoreModule = __webpack_require__(210); +var isCoreModule = __webpack_require__(211); module.exports = function isCore(x) { return isCoreModule(x); @@ -22131,16 +22150,16 @@ module.exports = function isCore(x) { /***/ }), -/* 218 */ +/* 219 */ /***/ (function(module, exports, __webpack_require__) { -var isCore = __webpack_require__(210); +var isCore = __webpack_require__(211); var fs = __webpack_require__(134); var path = __webpack_require__(4); -var getHomedir = __webpack_require__(205); -var caller = __webpack_require__(206); -var nodeModulesPaths = __webpack_require__(207); -var normalizeOptions = __webpack_require__(209); +var getHomedir = __webpack_require__(206); +var caller = __webpack_require__(207); +var nodeModulesPaths = __webpack_require__(208); +var normalizeOptions = __webpack_require__(210); var realpathFS = process.platform !== 'win32' && fs.realpathSync && typeof fs.realpathSync.native === 'function' ? fs.realpathSync.native : fs.realpathSync; @@ -22345,7 +22364,7 @@ module.exports = function resolveSync(x, options) { /***/ }), -/* 219 */ +/* 220 */ /***/ (function(module, exports) { module.exports = extractDescription @@ -22365,17 +22384,17 @@ function extractDescription (d) { /***/ }), -/* 220 */ +/* 221 */ /***/ (function(module) { module.exports = JSON.parse("{\"topLevel\":{\"dependancies\":\"dependencies\",\"dependecies\":\"dependencies\",\"depdenencies\":\"dependencies\",\"devEependencies\":\"devDependencies\",\"depends\":\"dependencies\",\"dev-dependencies\":\"devDependencies\",\"devDependences\":\"devDependencies\",\"devDepenencies\":\"devDependencies\",\"devdependencies\":\"devDependencies\",\"repostitory\":\"repository\",\"repo\":\"repository\",\"prefereGlobal\":\"preferGlobal\",\"hompage\":\"homepage\",\"hampage\":\"homepage\",\"autohr\":\"author\",\"autor\":\"author\",\"contributers\":\"contributors\",\"publicationConfig\":\"publishConfig\",\"script\":\"scripts\"},\"bugs\":{\"web\":\"url\",\"name\":\"url\"},\"script\":{\"server\":\"start\",\"tests\":\"test\"}}"); /***/ }), -/* 221 */ +/* 222 */ /***/ (function(module, exports, __webpack_require__) { var util = __webpack_require__(112) -var messages = __webpack_require__(222) +var messages = __webpack_require__(223) module.exports = function() { var args = Array.prototype.slice.call(arguments, 0) @@ -22400,20 +22419,20 @@ function makeTypoWarning (providedName, probableName, field) { /***/ }), -/* 222 */ +/* 223 */ /***/ (function(module) { module.exports = JSON.parse("{\"repositories\":\"'repositories' (plural) Not supported. Please pick one as the 'repository' field\",\"missingRepository\":\"No repository field.\",\"brokenGitUrl\":\"Probably broken git url: %s\",\"nonObjectScripts\":\"scripts must be an object\",\"nonStringScript\":\"script values must be string commands\",\"nonArrayFiles\":\"Invalid 'files' member\",\"invalidFilename\":\"Invalid filename in 'files' list: %s\",\"nonArrayBundleDependencies\":\"Invalid 'bundleDependencies' list. Must be array of package names\",\"nonStringBundleDependency\":\"Invalid bundleDependencies member: %s\",\"nonDependencyBundleDependency\":\"Non-dependency in bundleDependencies: %s\",\"nonObjectDependencies\":\"%s field must be an object\",\"nonStringDependency\":\"Invalid dependency: %s %s\",\"deprecatedArrayDependencies\":\"specifying %s as array is deprecated\",\"deprecatedModules\":\"modules field is deprecated\",\"nonArrayKeywords\":\"keywords should be an array of strings\",\"nonStringKeyword\":\"keywords should be an array of strings\",\"conflictingName\":\"%s is also the name of a node core module.\",\"nonStringDescription\":\"'description' field should be a string\",\"missingDescription\":\"No description\",\"missingReadme\":\"No README data\",\"missingLicense\":\"No license field.\",\"nonEmailUrlBugsString\":\"Bug string field must be url, email, or {email,url}\",\"nonUrlBugsUrlField\":\"bugs.url field must be a string url. Deleted.\",\"nonEmailBugsEmailField\":\"bugs.email field must be a string email. Deleted.\",\"emptyNormalizedBugs\":\"Normalized value of bugs field is an empty object. Deleted.\",\"nonUrlHomepage\":\"homepage field must be a string url. Deleted.\",\"invalidLicense\":\"license should be a valid SPDX license expression\",\"typo\":\"%s should probably be %s.\"}"); /***/ }), -/* 223 */ +/* 224 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const writeJsonFile = __webpack_require__(224); -const sortKeys = __webpack_require__(230); +const writeJsonFile = __webpack_require__(225); +const sortKeys = __webpack_require__(231); const dependencyKeys = new Set([ 'dependencies', @@ -22478,18 +22497,18 @@ module.exports.sync = (filePath, data, options) => { /***/ }), -/* 224 */ +/* 225 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const fs = __webpack_require__(133); -const writeFileAtomic = __webpack_require__(225); -const sortKeys = __webpack_require__(230); -const makeDir = __webpack_require__(232); -const pify = __webpack_require__(233); -const detectIndent = __webpack_require__(234); +const writeFileAtomic = __webpack_require__(226); +const sortKeys = __webpack_require__(231); +const makeDir = __webpack_require__(233); +const pify = __webpack_require__(234); +const detectIndent = __webpack_require__(235); const init = (fn, filePath, data, options) => { if (!filePath) { @@ -22561,7 +22580,7 @@ module.exports.sync = (filePath, data, options) => { /***/ }), -/* 225 */ +/* 226 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -22572,8 +22591,8 @@ module.exports._getTmpname = getTmpname // for testing module.exports._cleanupOnExit = cleanupOnExit var fs = __webpack_require__(133) -var MurmurHash3 = __webpack_require__(226) -var onExit = __webpack_require__(227) +var MurmurHash3 = __webpack_require__(227) +var onExit = __webpack_require__(228) var path = __webpack_require__(4) var activeFiles = {} @@ -22581,7 +22600,7 @@ var activeFiles = {} /* istanbul ignore next */ var threadId = (function getId () { try { - var workerThreads = __webpack_require__(229) + var workerThreads = __webpack_require__(230) /// if we are in main thread, this is set to `0` return workerThreads.threadId @@ -22806,7 +22825,7 @@ function writeFileSync (filename, data, options) { /***/ }), -/* 226 */ +/* 227 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -22948,7 +22967,7 @@ function writeFileSync (filename, data, options) { /***/ }), -/* 227 */ +/* 228 */ /***/ (function(module, exports, __webpack_require__) { // Note: since nyc uses this module to output coverage, any lines @@ -22977,10 +22996,10 @@ if (!processOk(process)) { } } else { var assert = __webpack_require__(140) - var signals = __webpack_require__(228) + var signals = __webpack_require__(229) var isWin = /^win/i.test(process.platform) - var EE = __webpack_require__(156) + var EE = __webpack_require__(157) /* istanbul ignore if */ if (typeof EE !== 'function') { EE = EE.EventEmitter @@ -23156,7 +23175,7 @@ if (!processOk(process)) { /***/ }), -/* 228 */ +/* 229 */ /***/ (function(module, exports) { // This is not the set of all possible signals. @@ -23215,18 +23234,18 @@ if (process.platform === 'linux') { /***/ }), -/* 229 */ +/* 230 */ /***/ (function(module, exports) { module.exports = require(undefined); /***/ }), -/* 230 */ +/* 231 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const isPlainObj = __webpack_require__(231); +const isPlainObj = __webpack_require__(232); module.exports = (obj, opts) => { if (!isPlainObj(obj)) { @@ -23283,7 +23302,7 @@ module.exports = (obj, opts) => { /***/ }), -/* 231 */ +/* 232 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -23297,15 +23316,15 @@ module.exports = function (x) { /***/ }), -/* 232 */ +/* 233 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); const path = __webpack_require__(4); -const pify = __webpack_require__(233); -const semver = __webpack_require__(190); +const pify = __webpack_require__(234); +const semver = __webpack_require__(191); const defaults = { mode: 0o777 & (~process.umask()), @@ -23443,7 +23462,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 233 */ +/* 234 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -23518,7 +23537,7 @@ module.exports = (input, options) => { /***/ }), -/* 234 */ +/* 235 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -23647,7 +23666,7 @@ module.exports = str => { /***/ }), -/* 235 */ +/* 236 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -23661,7 +23680,7 @@ exports.runScriptInPackage = runScriptInPackage; exports.runScriptInPackageStreaming = runScriptInPackageStreaming; exports.yarnWorkspacesInfo = yarnWorkspacesInfo; -var _child_process = __webpack_require__(236); +var _child_process = __webpack_require__(237); /* * SPDX-License-Identifier: Apache-2.0 @@ -23752,7 +23771,7 @@ async function yarnWorkspacesInfo(directory) { } /***/ }), -/* 236 */ +/* 237 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -23768,11 +23787,11 @@ var _stream = __webpack_require__(138); var _chalk = _interopRequireDefault(__webpack_require__(113)); -var _execa = _interopRequireDefault(__webpack_require__(237)); +var _execa = _interopRequireDefault(__webpack_require__(238)); -var _strongLogTransformer = _interopRequireDefault(__webpack_require__(273)); +var _strongLogTransformer = _interopRequireDefault(__webpack_require__(274)); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -23861,23 +23880,23 @@ function spawnStreaming(command, args, opts, { } /***/ }), -/* 237 */ +/* 238 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const childProcess = __webpack_require__(238); -const crossSpawn = __webpack_require__(239); -const stripFinalNewline = __webpack_require__(252); -const npmRunPath = __webpack_require__(253); -const onetime = __webpack_require__(254); -const makeError = __webpack_require__(256); -const normalizeStdio = __webpack_require__(261); -const {spawnedKill, spawnedCancel, setupTimeout, setExitHandler} = __webpack_require__(262); -const {handleInput, getSpawnedResult, makeAllStream, validateInputSync} = __webpack_require__(263); -const {mergePromise, getSpawnedPromise} = __webpack_require__(271); -const {joinCommand, parseCommand} = __webpack_require__(272); +const childProcess = __webpack_require__(239); +const crossSpawn = __webpack_require__(240); +const stripFinalNewline = __webpack_require__(253); +const npmRunPath = __webpack_require__(254); +const onetime = __webpack_require__(255); +const makeError = __webpack_require__(257); +const normalizeStdio = __webpack_require__(262); +const {spawnedKill, spawnedCancel, setupTimeout, setExitHandler} = __webpack_require__(263); +const {handleInput, getSpawnedResult, makeAllStream, validateInputSync} = __webpack_require__(264); +const {mergePromise, getSpawnedPromise} = __webpack_require__(272); +const {joinCommand, parseCommand} = __webpack_require__(273); const DEFAULT_MAX_BUFFER = 1000 * 1000 * 100; @@ -24128,21 +24147,21 @@ module.exports.node = (scriptPath, args, options = {}) => { /***/ }), -/* 238 */ +/* 239 */ /***/ (function(module, exports) { module.exports = require("child_process"); /***/ }), -/* 239 */ +/* 240 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const cp = __webpack_require__(238); -const parse = __webpack_require__(240); -const enoent = __webpack_require__(251); +const cp = __webpack_require__(239); +const parse = __webpack_require__(241); +const enoent = __webpack_require__(252); function spawn(command, args, options) { // Parse the arguments @@ -24180,16 +24199,16 @@ module.exports._enoent = enoent; /***/ }), -/* 240 */ +/* 241 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const resolveCommand = __webpack_require__(241); -const escape = __webpack_require__(247); -const readShebang = __webpack_require__(248); +const resolveCommand = __webpack_require__(242); +const escape = __webpack_require__(248); +const readShebang = __webpack_require__(249); const isWin = process.platform === 'win32'; const isExecutableRegExp = /\.(?:com|exe)$/i; @@ -24278,15 +24297,15 @@ module.exports = parse; /***/ }), -/* 241 */ +/* 242 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const which = __webpack_require__(242); -const getPathKey = __webpack_require__(246); +const which = __webpack_require__(243); +const getPathKey = __webpack_require__(247); function resolveCommandAttempt(parsed, withoutPathExt) { const env = parsed.options.env || process.env; @@ -24337,7 +24356,7 @@ module.exports = resolveCommand; /***/ }), -/* 242 */ +/* 243 */ /***/ (function(module, exports, __webpack_require__) { const isWindows = process.platform === 'win32' || @@ -24346,7 +24365,7 @@ const isWindows = process.platform === 'win32' || const path = __webpack_require__(4) const COLON = isWindows ? ';' : ':' -const isexe = __webpack_require__(243) +const isexe = __webpack_require__(244) const getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }) @@ -24468,15 +24487,15 @@ which.sync = whichSync /***/ }), -/* 243 */ +/* 244 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(134) var core if (process.platform === 'win32' || global.TESTING_WINDOWS) { - core = __webpack_require__(244) -} else { core = __webpack_require__(245) +} else { + core = __webpack_require__(246) } module.exports = isexe @@ -24531,7 +24550,7 @@ function sync (path, options) { /***/ }), -/* 244 */ +/* 245 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -24579,7 +24598,7 @@ function sync (path, options) { /***/ }), -/* 245 */ +/* 246 */ /***/ (function(module, exports, __webpack_require__) { module.exports = isexe @@ -24626,7 +24645,7 @@ function checkMode (stat, options) { /***/ }), -/* 246 */ +/* 247 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -24649,7 +24668,7 @@ module.exports.default = pathKey; /***/ }), -/* 247 */ +/* 248 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -24701,14 +24720,14 @@ module.exports.argument = escapeArgument; /***/ }), -/* 248 */ +/* 249 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const shebangCommand = __webpack_require__(249); +const shebangCommand = __webpack_require__(250); function readShebang(command) { // Read the first 150 bytes from the file @@ -24731,12 +24750,12 @@ module.exports = readShebang; /***/ }), -/* 249 */ +/* 250 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const shebangRegex = __webpack_require__(250); +const shebangRegex = __webpack_require__(251); module.exports = (string = '') => { const match = string.match(shebangRegex); @@ -24757,7 +24776,7 @@ module.exports = (string = '') => { /***/ }), -/* 250 */ +/* 251 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -24766,7 +24785,7 @@ module.exports = /^#!(.*)/; /***/ }), -/* 251 */ +/* 252 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -24832,7 +24851,7 @@ module.exports = { /***/ }), -/* 252 */ +/* 253 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -24855,13 +24874,13 @@ module.exports = input => { /***/ }), -/* 253 */ +/* 254 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathKey = __webpack_require__(246); +const pathKey = __webpack_require__(247); const npmRunPath = options => { options = { @@ -24909,12 +24928,12 @@ module.exports.env = options => { /***/ }), -/* 254 */ +/* 255 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(255); +const mimicFn = __webpack_require__(256); const calledFunctions = new WeakMap(); @@ -24960,7 +24979,7 @@ module.exports.callCount = function_ => { /***/ }), -/* 255 */ +/* 256 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -24980,12 +24999,12 @@ module.exports.default = mimicFn; /***/ }), -/* 256 */ +/* 257 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const {signalsByName} = __webpack_require__(257); +const {signalsByName} = __webpack_require__(258); const getErrorPrefix = ({timedOut, timeout, errorCode, signal, signalDescription, exitCode, isCanceled}) => { if (timedOut) { @@ -25073,14 +25092,14 @@ module.exports = makeError; /***/ }), -/* 257 */ +/* 258 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports,"__esModule",{value:true});exports.signalsByNumber=exports.signalsByName=void 0;var _os=__webpack_require__(121); -var _signals=__webpack_require__(258); -var _realtime=__webpack_require__(260); +var _signals=__webpack_require__(259); +var _realtime=__webpack_require__(261); @@ -25150,14 +25169,14 @@ const signalsByNumber=getSignalsByNumber();exports.signalsByNumber=signalsByNumb //# sourceMappingURL=main.js.map /***/ }), -/* 258 */ +/* 259 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports,"__esModule",{value:true});exports.getSignals=void 0;var _os=__webpack_require__(121); -var _core=__webpack_require__(259); -var _realtime=__webpack_require__(260); +var _core=__webpack_require__(260); +var _realtime=__webpack_require__(261); @@ -25191,7 +25210,7 @@ return{name,number,description,supported,action,forced,standard}; //# sourceMappingURL=signals.js.map /***/ }), -/* 259 */ +/* 260 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25470,7 +25489,7 @@ standard:"other"}];exports.SIGNALS=SIGNALS; //# sourceMappingURL=core.js.map /***/ }), -/* 260 */ +/* 261 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25495,7 +25514,7 @@ const SIGRTMAX=64;exports.SIGRTMAX=SIGRTMAX; //# sourceMappingURL=realtime.js.map /***/ }), -/* 261 */ +/* 262 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25554,13 +25573,13 @@ module.exports.node = opts => { /***/ }), -/* 262 */ +/* 263 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const os = __webpack_require__(121); -const onExit = __webpack_require__(227); +const onExit = __webpack_require__(228); const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5; @@ -25673,14 +25692,14 @@ module.exports = { /***/ }), -/* 263 */ +/* 264 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const isStream = __webpack_require__(264); -const getStream = __webpack_require__(265); -const mergeStream = __webpack_require__(270); +const isStream = __webpack_require__(265); +const getStream = __webpack_require__(266); +const mergeStream = __webpack_require__(271); // `input` option const handleInput = (spawned, input) => { @@ -25777,7 +25796,7 @@ module.exports = { /***/ }), -/* 264 */ +/* 265 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -25812,14 +25831,14 @@ module.exports = isStream; /***/ }), -/* 265 */ +/* 266 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const {constants: BufferConstants} = __webpack_require__(266); -const pump = __webpack_require__(267); -const bufferStream = __webpack_require__(269); +const {constants: BufferConstants} = __webpack_require__(267); +const pump = __webpack_require__(268); +const bufferStream = __webpack_require__(270); class MaxBufferError extends Error { constructor() { @@ -25879,17 +25898,17 @@ module.exports.MaxBufferError = MaxBufferError; /***/ }), -/* 266 */ +/* 267 */ /***/ (function(module, exports) { module.exports = require("buffer"); /***/ }), -/* 267 */ +/* 268 */ /***/ (function(module, exports, __webpack_require__) { -var once = __webpack_require__(162) -var eos = __webpack_require__(268) +var once = __webpack_require__(163) +var eos = __webpack_require__(269) var fs = __webpack_require__(134) // we only need fs to get the ReadStream and WriteStream prototypes var noop = function () {} @@ -25973,10 +25992,10 @@ module.exports = pump /***/ }), -/* 268 */ +/* 269 */ /***/ (function(module, exports, __webpack_require__) { -var once = __webpack_require__(162); +var once = __webpack_require__(163); var noop = function() {}; @@ -26073,7 +26092,7 @@ module.exports = eos; /***/ }), -/* 269 */ +/* 270 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26132,7 +26151,7 @@ module.exports = options => { /***/ }), -/* 270 */ +/* 271 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26180,7 +26199,7 @@ module.exports = function (/*streams...*/) { /***/ }), -/* 271 */ +/* 272 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26233,7 +26252,7 @@ module.exports = { /***/ }), -/* 272 */ +/* 273 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26272,7 +26291,7 @@ module.exports = { /***/ }), -/* 273 */ +/* 274 */ /***/ (function(module, exports, __webpack_require__) { // Copyright IBM Corp. 2014,2018. All Rights Reserved. @@ -26280,12 +26299,12 @@ module.exports = { // This file is licensed under the Apache License 2.0. // License text available at https://opensource.org/licenses/Apache-2.0 -module.exports = __webpack_require__(274); -module.exports.cli = __webpack_require__(278); +module.exports = __webpack_require__(275); +module.exports.cli = __webpack_require__(279); /***/ }), -/* 274 */ +/* 275 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26300,9 +26319,9 @@ var stream = __webpack_require__(138); var util = __webpack_require__(112); var fs = __webpack_require__(134); -var through = __webpack_require__(275); -var duplexer = __webpack_require__(276); -var StringDecoder = __webpack_require__(277).StringDecoder; +var through = __webpack_require__(276); +var duplexer = __webpack_require__(277); +var StringDecoder = __webpack_require__(278).StringDecoder; module.exports = Logger; @@ -26491,7 +26510,7 @@ function lineMerger(host) { /***/ }), -/* 275 */ +/* 276 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(138) @@ -26605,7 +26624,7 @@ function through (write, end, opts) { /***/ }), -/* 276 */ +/* 277 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(138) @@ -26698,13 +26717,13 @@ function duplex(writer, reader) { /***/ }), -/* 277 */ +/* 278 */ /***/ (function(module, exports) { module.exports = require("string_decoder"); /***/ }), -/* 278 */ +/* 279 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -26715,11 +26734,11 @@ module.exports = require("string_decoder"); -var minimist = __webpack_require__(279); +var minimist = __webpack_require__(280); var path = __webpack_require__(4); -var Logger = __webpack_require__(274); -var pkg = __webpack_require__(280); +var Logger = __webpack_require__(275); +var pkg = __webpack_require__(281); module.exports = cli; @@ -26773,7 +26792,7 @@ function usage($0, p) { /***/ }), -/* 279 */ +/* 280 */ /***/ (function(module, exports) { module.exports = function (args, opts) { @@ -27028,13 +27047,13 @@ function isConstructorOrProto (obj, key) { /***/ }), -/* 280 */ +/* 281 */ /***/ (function(module) { module.exports = JSON.parse("{\"name\":\"strong-log-transformer\",\"version\":\"2.1.0\",\"description\":\"Stream transformer that prefixes lines with timestamps and other things.\",\"author\":\"Ryan Graham \",\"license\":\"Apache-2.0\",\"repository\":{\"type\":\"git\",\"url\":\"git://github.com/strongloop/strong-log-transformer\"},\"keywords\":[\"logging\",\"streams\"],\"bugs\":{\"url\":\"https://github.com/strongloop/strong-log-transformer/issues\"},\"homepage\":\"https://github.com/strongloop/strong-log-transformer\",\"directories\":{\"test\":\"test\"},\"bin\":{\"sl-log-transformer\":\"bin/sl-log-transformer.js\"},\"main\":\"index.js\",\"scripts\":{\"test\":\"tap --100 test/test-*\"},\"dependencies\":{\"duplexer\":\"^0.1.1\",\"minimist\":\"^1.2.0\",\"through\":\"^2.3.4\"},\"devDependencies\":{\"tap\":\"^12.0.1\"},\"engines\":{\"node\":\">=4\"}}"); /***/ }), -/* 281 */ +/* 282 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27046,19 +27065,19 @@ Object.defineProperty(exports, "__esModule", { exports.copyWorkspacePackages = copyWorkspacePackages; exports.workspacePackagePaths = workspacePackagePaths; -var _glob = _interopRequireDefault(__webpack_require__(147)); +var _glob = _interopRequireDefault(__webpack_require__(148)); var _path = _interopRequireDefault(__webpack_require__(4)); var _util = __webpack_require__(112); -var _config = __webpack_require__(282); +var _config = __webpack_require__(283); var _fs = __webpack_require__(131); -var _package_json = __webpack_require__(165); +var _package_json = __webpack_require__(166); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -27160,7 +27179,7 @@ function packagesFromGlobPattern({ } /***/ }), -/* 282 */ +/* 283 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27238,7 +27257,7 @@ function getProjectPaths({ } /***/ }), -/* 283 */ +/* 284 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27249,15 +27268,13 @@ Object.defineProperty(exports, "__esModule", { }); exports.getAllChecksums = getAllChecksums; -var _fs = _interopRequireDefault(__webpack_require__(134)); - -var _crypto = _interopRequireDefault(__webpack_require__(284)); +var _promises = __webpack_require__(143); -var _util = __webpack_require__(112); +var _crypto = _interopRequireDefault(__webpack_require__(285)); -var _execa = _interopRequireDefault(__webpack_require__(237)); +var _execa = _interopRequireDefault(__webpack_require__(238)); -var _yarn_lock = __webpack_require__(285); +var _yarn_lock = __webpack_require__(286); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -27290,8 +27307,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * specific language governing permissions and limitations * under the License. */ -const statAsync = (0, _util.promisify)(_fs.default.stat); - const projectBySpecificitySorter = (a, b) => b.path.length - a.path.length; /** Get the changed files for a set of projects */ @@ -27408,7 +27423,7 @@ async function getChecksum(project, changes, yarnLock, osd, log) { return `${path}:deleted`; } - const stats = await statAsync(osd.getAbsolute(path)); + const stats = await (0, _promises.stat)(osd.getAbsolute(path)); log.verbose(`[${project.name}] modified time ${stats.mtimeMs} for ${path}`); return `${path}:${stats.mtimeMs}`; })); @@ -27466,13 +27481,13 @@ async function getAllChecksums(osd, log, yarnLock) { } /***/ }), -/* 284 */ +/* 285 */ /***/ (function(module, exports) { module.exports = require("crypto"); /***/ }), -/* 285 */ +/* 286 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -27484,7 +27499,11 @@ Object.defineProperty(exports, "__esModule", { exports.readYarnLock = readYarnLock; exports.resolveDepsForProject = resolveDepsForProject; -var _lockfile = __webpack_require__(286); +var _lockfile = __webpack_require__(287); + +var _crossPlatform = __webpack_require__(288); + +var _path = __webpack_require__(4); var _fs = __webpack_require__(131); @@ -27524,7 +27543,7 @@ async function readYarnLock(osd) { const yarnLock = (0, _lockfile.parse)(contents); if (yarnLock.type === 'success') { - return yarnLock.object; + return fixFileLinks(yarnLock.object); } throw new Error('unable to read yarn.lock file, please run `yarn osd bootstrap`'); @@ -27536,6 +27555,32 @@ async function readYarnLock(osd) { return {}; } +/** + * Converts relative `file:` paths to absolute paths + * Yarn parsing method converts all file URIs to relative paths and this + * breaks the single-version requirement as dependencies to the same path + * would differ in their URIs across OSD and packages. + */ + + +function fixFileLinks(yarnLock) { + const fileLinkDelimiter = '@file:'; + const linkedKeys = Object.keys(yarnLock).filter(key => key.includes(fileLinkDelimiter)); + if (linkedKeys.length === 0) return yarnLock; + const updatedYarnLock = { ...yarnLock + }; + + for (const key of linkedKeys) { + const [keyName, keyPath, ...rest] = key.split(fileLinkDelimiter); + + if (!(0, _path.isAbsolute)(keyPath)) { + const updatedKeyName = [keyName, (0, _crossPlatform.standardize)((0, _path.resolve)(keyPath)), ...rest].join(fileLinkDelimiter); + updatedYarnLock[updatedKeyName] = updatedYarnLock[key]; + } + } + + return updatedYarnLock; +} /** * Get a list of the absolute dependencies of this project, as resolved * in the yarn.lock file, does not include other projects in the workspace @@ -27608,7 +27653,7 @@ function resolveDepsForProject({ } /***/ }), -/* 286 */ +/* 287 */ /***/ (function(module, exports, __webpack_require__) { module.exports = @@ -29167,7 +29212,7 @@ module.exports = invariant; /* 9 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(284); +module.exports = __webpack_require__(285); /***/ }), /* 10 */, @@ -30117,7 +30162,7 @@ exports.f = __webpack_require__(33) ? Object.defineProperty : function definePro /* 54 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(156); +module.exports = __webpack_require__(157); /***/ }), /* 55 */ @@ -31491,7 +31536,7 @@ function onceStrict (fn) { /* 63 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(266); +module.exports = __webpack_require__(267); /***/ }), /* 64 */, @@ -37886,117 +37931,226 @@ module.exports = process && support(supportLevel); /******/ ]); /***/ }), -/* 287 */ +/* 288 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ Object.defineProperty(exports, "__esModule", { value: true }); -exports.BootstrapCacheFile = void 0; -var _fs = _interopRequireDefault(__webpack_require__(134)); +const tslib_1 = __webpack_require__(7); -var _path = _interopRequireDefault(__webpack_require__(4)); +tslib_1.__exportStar(__webpack_require__(289), exports); -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +tslib_1.__exportStar(__webpack_require__(290), exports); -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +tslib_1.__exportStar(__webpack_require__(291), exports); -class BootstrapCacheFile { - constructor(osd, project, checksums) { - _defineProperty(this, "path", void 0); +/***/ }), +/* 289 */ +/***/ (function(module, exports, __webpack_require__) { - _defineProperty(this, "expectedValue", void 0); +"use strict"; - this.path = _path.default.resolve(project.targetLocation, '.bootstrap-cache'); +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ - if (!checksums) { - return; - } +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.realshortpathSync = exports.realShortPathSync = exports.realpathSync = exports.realPathSync = exports.resolveToShortNameSync = exports.resolveToShortPathSync = exports.resolveToFullNameSync = exports.resolveToFullPathSync = exports.shortNameSupportedSync = exports.shortNamesSupportedSync = exports.standardize = exports.NAMESPACE_PREFIX = void 0; - const projectAndDepCacheKeys = Array.from(osd.getProjectAndDeps(project.name).values()) // sort deps by name so that the key is stable - .sort((a, b) => a.name.localeCompare(b.name)) // get the cacheKey for each project, return undefined if the cache key couldn't be determined - .map(p => { - const cacheKey = checksums.get(p.name); +const child_process_1 = __webpack_require__(239); - if (cacheKey) { - return `${p.name}:${cacheKey}`; - } - }); // if any of the relevant cache keys are undefined then the projectCacheKey must be too +const path_1 = __webpack_require__(4); - this.expectedValue = projectAndDepCacheKeys.some(k => !k) ? undefined : [`# this is only human readable for debugging, please don't try to parse this`, ...projectAndDepCacheKeys].join('\n'); - } +const fs_1 = __webpack_require__(134); - isValid() { - if (!this.expectedValue) { - return false; - } +exports.NAMESPACE_PREFIX = process.platform === 'win32' ? '\\\\?\\' : ''; +/** + * Get a standardized reference to a path + * @param {string} path - the path to standardize + * @param {boolean} [usePosix=true] - produce a posix reference + * @param {boolean} [escapedBackslashes=true] - on Windows, double-backslash the reference + * @param {boolean} [returnUNC=false] - produce an extended reference + */ - try { - return _fs.default.readFileSync(this.path, 'utf8') === this.expectedValue; - } catch (error) { - if (error.code === 'ENOENT') { - return false; - } +exports.standardize = (path, usePosix = true, escapedBackslashes = true, returnUNC = false) => { + var _process; - throw error; - } - } + // Force os-dependant separators + const normal = path_1.normalize(path); // Filter out in-browser executions as well as non-windows ones - delete() { - try { - _fs.default.unlinkSync(this.path); - } catch (error) { - if (error.code !== 'ENOENT') { - throw error; - } - } + if (((_process = process) === null || _process === void 0 ? void 0 : _process.platform) !== 'win32') return normal; + if (usePosix) return normal.replace(/\\/g, '/');else if (escapedBackslashes) return normal.replace(/\\/g, '\\\\');else if (returnUNC) return '\\\\?\\' + normal; + return normal; +}; +/** + * Windows-only function that uses PowerShell to calculate the full path + * @param {string} path + * @private + */ + + +const getFullPathSync = path => { + if (process.platform !== 'win32') return path; + + try { + var _child_process_1$exec, _child_process_1$exec2; + + const fullName = (_child_process_1$exec = child_process_1.execSync(`powershell "(Get-Item -LiteralPath '${path}').FullName"`, { + encoding: 'utf8' + })) === null || _child_process_1$exec === void 0 ? void 0 : (_child_process_1$exec2 = _child_process_1$exec.trim) === null || _child_process_1$exec2 === void 0 ? void 0 : _child_process_1$exec2.call(_child_process_1$exec); // Make sure we got something back + + if ((fullName === null || fullName === void 0 ? void 0 : fullName.length) > 2) return fullName; + } catch (ex) {// Do nothing } - write() { - if (!this.expectedValue) { - return; - } + return path; +}; +/** + * Windows-only function that uses PowerShell and Com Object to calculate the 8.3 path + * @param {string} path + * @private + */ - _fs.default.mkdirSync(_path.default.dirname(this.path), { - recursive: true - }); - _fs.default.writeFileSync(this.path, this.expectedValue); +const getShortPathSync = path => { + if (process.platform !== 'win32') return path; + + try { + var _child_process_1$exec3, _child_process_1$exec4; + + const shortPath = (_child_process_1$exec3 = child_process_1.execSync(`powershell "$FSO = New-Object -ComObject Scripting.FileSystemObject; $O = (Get-Item -LiteralPath '${path}'); if ($O.PSIsContainer) { $FSO.GetFolder($O.FullName).ShortPath } else { $FSO.GetFile($O.FullName).ShortPath }"`, { + encoding: 'utf8' + })) === null || _child_process_1$exec3 === void 0 ? void 0 : (_child_process_1$exec4 = _child_process_1$exec3.trim) === null || _child_process_1$exec4 === void 0 ? void 0 : _child_process_1$exec4.call(_child_process_1$exec3); // Make sure we got something back + + if ((shortPath === null || shortPath === void 0 ? void 0 : shortPath.length) > 2) return shortPath; + } catch (ex) {// Do nothing } -} + return path; +}; +/** + * Checks if Windows 8.3 short names are supported on the volume of the given path + * @param {string} [path='.'] - the path to examine + */ -exports.BootstrapCacheFile = BootstrapCacheFile; + +exports.shortNamesSupportedSync = (path = '.') => { + if (process.platform !== 'win32') return false; + const testFileName = '.___osd-cross-platform-test.file'; + const file = path_1.resolve(path, testFileName); // Create a test file if it doesn't exist + + if (!fs_1.existsSync(file)) fs_1.closeSync(fs_1.openSync(file, 'w')); // If the returned value's basename is not the same as the requested file name, it must be a short name + + const foundShortName = path_1.basename(getShortPathSync(file)) !== testFileName; // Cleanup + + fs_1.unlinkSync(file); + return foundShortName; +}; +/** + * @borrows shortNamesSupportedSync + */ + + +exports.shortNameSupportedSync = exports.shortNamesSupportedSync; +/** + * Get the full pathname + * @param {string} path - the path to resolve + */ + +exports.resolveToFullPathSync = path => getFullPathSync(path_1.resolve(path)); +/** + * @borrows resolveToFullPathSync + */ + + +exports.resolveToFullNameSync = exports.resolveToFullPathSync; +/** + * Get the short pathname + * @param {string} path - the path to resolve + */ + +exports.resolveToShortPathSync = path => getShortPathSync(path_1.resolve(path)); +/** + * @borrows resolveToShortPathSync + */ + + +exports.resolveToShortNameSync = exports.resolveToShortPathSync; +/** + * Get the canonical pathname + * @param {string} path - the path to resolve + */ + +exports.realPathSync = path => getFullPathSync(fs_1.realpathSync(path, 'utf8')); +/** + * @borrows realPathSync + */ + + +exports.realpathSync = exports.realPathSync; +/** + * Get the canonical pathname + * @param {string} path - the path to resolve + */ + +exports.realShortPathSync = path => getShortPathSync(fs_1.realpathSync(path, 'utf8')); +/** + * @borrows realShortPathSync + */ + + +exports.realshortpathSync = exports.realShortPathSync; /***/ }), -/* 288 */ +/* 290 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ Object.defineProperty(exports, "__esModule", { value: true }); -exports.validateDependencies = validateDependencies; - -var _lockfile = __webpack_require__(286); +exports.PROCESS_POSIX_WORKING_DIR = exports.PROCESS_WORKING_DIR = void 0; -var _dedent = _interopRequireDefault(__webpack_require__(2)); +const path_1 = __webpack_require__(289); +/** + * The full pathname of the working directory of the process + * @constant + * @type {string} + */ -var _chalk = _interopRequireDefault(__webpack_require__(113)); -var _fs = __webpack_require__(131); +exports.PROCESS_WORKING_DIR = path_1.resolveToFullPathSync(process.cwd()); +/** + * The full pathname of the working directory of the process, in POSIX format + * @constant + * @type {string} + */ -var _log = __webpack_require__(144); +exports.PROCESS_POSIX_WORKING_DIR = path_1.standardize(exports.PROCESS_WORKING_DIR); -var _projects_tree = __webpack_require__(289); +/***/ }), +/* 291 */ +/***/ (function(module, exports, __webpack_require__) { -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +"use strict"; /* * SPDX-License-Identifier: Apache-2.0 @@ -38009,6 +38163,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * GitHub history for details. */ +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.relativeToRepoRoot = exports.getRepoRoot = exports.getMatchingRoot = exports.UPSTREAM_BRANCH = exports.REPO_ROOT_8_3 = exports.REPO_ROOT = void 0; + +const tslib_1 = __webpack_require__(7); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -38027,48 +38187,319 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * specific language governing permissions and limitations * under the License. */ -// @ts-expect-error published types are useless -async function validateDependencies(osd, yarnLock) { - // look through all of the packages in the yarn.lock file to see if - // we have accidentally installed multiple lodash v4 versions - const lodash4Versions = new Set(); - const lodash4Reqs = new Set(); - - for (const [req, dep] of Object.entries(yarnLock)) { - if (req.startsWith('lodash@') && dep.version.startsWith('4.')) { - lodash4Reqs.add(req); - lodash4Versions.add(dep.version); - } - } // if we find more than one lodash v4 version installed then delete - // lodash v4 requests from the yarn.lock file and prompt the user to - // retry bootstrap so that a single v4 version will be installed - - - if (lodash4Versions.size > 1) { - for (const req of lodash4Reqs) { - delete yarnLock[req]; - } - await (0, _fs.writeFile)(osd.getAbsolute('yarn.lock'), (0, _lockfile.stringify)(yarnLock), 'utf8'); - _log.log.error((0, _dedent.default)` +const path_1 = __webpack_require__(4); - Multiple version of lodash v4 were detected, so they have been removed - from the yarn.lock file. Please rerun yarn osd bootstrap to coalese the - lodash versions installed. +const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(292)); - If you still see this error when you re-bootstrap then you might need - to force a new dependency to use the latest version of lodash via the - "resolutions" field in package.json. +const path_2 = __webpack_require__(289); - If you have questions about this please reach out to the operations team. +const readOpenSearchDashboardsPkgJson = dir => { + try { + const path = path_1.resolve(dir, 'package.json'); + const json = load_json_file_1.default.sync(path); - `); + if ((json === null || json === void 0 ? void 0 : json.name) === 'opensearch-dashboards') { + return json; + } + } catch (error) { + if (error && error.code === 'ENOENT') { + return; + } - process.exit(1); - } // look through all the dependencies of production packages and production - // dependencies of those packages to determine if we're shipping any versions - // of lodash v3 in the distributable + throw error; + } +}; + +const findOpenSearchDashboardsPackageJson = () => { + // search for the opensearch-dashboards directory, since this file is moved around it might + // not be where we think but should always be a relatively close parent + // of this directory + const startDir = path_2.realPathSync(__dirname); + const { + root: rootDir + } = path_1.parse(startDir); + let cursor = startDir; + + while (true) { + const opensearchDashboardsPkgJson = readOpenSearchDashboardsPkgJson(cursor); + + if (opensearchDashboardsPkgJson) { + return { + opensearchDashboardsDir: cursor, + opensearchDashboardsPkgJson: opensearchDashboardsPkgJson + }; + } + + const parent = path_1.dirname(cursor); + + if (parent === rootDir) { + throw new Error(`unable to find opensearch-dashboards directory from ${startDir}`); + } + + cursor = parent; + } +}; + +const { + opensearchDashboardsDir, + opensearchDashboardsPkgJson +} = findOpenSearchDashboardsPackageJson(); +exports.REPO_ROOT = path_2.resolveToFullPathSync(opensearchDashboardsDir); +exports.REPO_ROOT_8_3 = path_2.resolveToShortPathSync(opensearchDashboardsDir); +exports.UPSTREAM_BRANCH = opensearchDashboardsPkgJson.branch; + +exports.getMatchingRoot = (path, rootPaths) => { + const rootPathsArray = Array.isArray(rootPaths) ? rootPaths : [rootPaths]; // We can only find the appropriate root if an absolute path was given + + if (path && path_1.isAbsolute(path)) { + // Return the matching root if one is found or return `undefined` + return rootPathsArray.find(root => path.startsWith(root)); + } + + return undefined; +}; + +exports.getRepoRoot = path => exports.getMatchingRoot(path, [exports.REPO_ROOT, exports.REPO_ROOT_8_3]); + +exports.relativeToRepoRoot = path => { + const repoRoot = exports.getRepoRoot(path); + return repoRoot ? path_1.relative(repoRoot, path) : null; +}; + +/***/ }), +/* 292 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const path = __webpack_require__(4); +const {promisify} = __webpack_require__(112); +const fs = __webpack_require__(133); +const stripBom = __webpack_require__(293); +const parseJson = __webpack_require__(168); + +const parse = (data, filePath, options = {}) => { + data = stripBom(data); + + if (typeof options.beforeParse === 'function') { + data = options.beforeParse(data); + } + + return parseJson(data, options.reviver, path.relative(process.cwd(), filePath)); +}; + +module.exports = async (filePath, options) => parse(await promisify(fs.readFile)(filePath, 'utf8'), filePath, options); +module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'utf8'), filePath, options); + + +/***/ }), +/* 293 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = string => { + if (typeof string !== 'string') { + throw new TypeError(`Expected a string, got ${typeof string}`); + } + + // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string + // conversion translates it to FEFF (UTF-16 BOM) + if (string.charCodeAt(0) === 0xFEFF) { + return string.slice(1); + } + + return string; +}; + + +/***/ }), +/* 294 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.BootstrapCacheFile = void 0; + +var _fs = _interopRequireDefault(__webpack_require__(134)); + +var _path = _interopRequireDefault(__webpack_require__(4)); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +class BootstrapCacheFile { + constructor(osd, project, checksums) { + _defineProperty(this, "path", void 0); + + _defineProperty(this, "expectedValue", void 0); + + this.path = _path.default.resolve(project.targetLocation, '.bootstrap-cache'); + + if (!checksums) { + return; + } + + const projectAndDepCacheKeys = Array.from(osd.getProjectAndDeps(project.name).values()) // sort deps by name so that the key is stable + .sort((a, b) => a.name.localeCompare(b.name)) // get the cacheKey for each project, return undefined if the cache key couldn't be determined + .map(p => { + const cacheKey = checksums.get(p.name); + + if (cacheKey) { + return `${p.name}:${cacheKey}`; + } + }); // if any of the relevant cache keys are undefined then the projectCacheKey must be too + + this.expectedValue = projectAndDepCacheKeys.some(k => !k) ? undefined : [`# this is only human readable for debugging, please don't try to parse this`, ...projectAndDepCacheKeys].join('\n'); + } + + isValid() { + if (!this.expectedValue) { + return false; + } + + try { + return _fs.default.readFileSync(this.path, 'utf8') === this.expectedValue; + } catch (error) { + if (error.code === 'ENOENT') { + return false; + } + + throw error; + } + } + + delete() { + try { + _fs.default.unlinkSync(this.path); + } catch (error) { + if (error.code !== 'ENOENT') { + throw error; + } + } + } + + write() { + if (!this.expectedValue) { + return; + } + + _fs.default.mkdirSync(_path.default.dirname(this.path), { + recursive: true + }); + + _fs.default.writeFileSync(this.path, this.expectedValue); + } + +} + +exports.BootstrapCacheFile = BootstrapCacheFile; + +/***/ }), +/* 295 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.validateDependencies = validateDependencies; + +var _lockfile = __webpack_require__(287); + +var _dedent = _interopRequireDefault(__webpack_require__(2)); + +var _chalk = _interopRequireDefault(__webpack_require__(113)); + +var _fs = __webpack_require__(131); + +var _log = __webpack_require__(145); + +var _projects_tree = __webpack_require__(296); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +// @ts-expect-error published types are useless +async function validateDependencies(osd, yarnLock) { + // look through all of the packages in the yarn.lock file to see if + // we have accidentally installed multiple lodash v4 versions + const lodash4Versions = new Set(); + const lodash4Reqs = new Set(); + + for (const [req, dep] of Object.entries(yarnLock)) { + if (req.startsWith('lodash@') && dep.version.startsWith('4.')) { + lodash4Reqs.add(req); + lodash4Versions.add(dep.version); + } + } // if we find more than one lodash v4 version installed then delete + // lodash v4 requests from the yarn.lock file and prompt the user to + // retry bootstrap so that a single v4 version will be installed + + + if (lodash4Versions.size > 1) { + for (const req of lodash4Reqs) { + delete yarnLock[req]; + } + + await (0, _fs.writeFile)(osd.getAbsolute('yarn.lock'), (0, _lockfile.stringify)(yarnLock), 'utf8'); + + _log.log.error((0, _dedent.default)` + + Multiple version of lodash v4 were detected, so they have been removed + from the yarn.lock file. Please rerun yarn osd bootstrap to coalese the + lodash versions installed. + + If you still see this error when you re-bootstrap then you might need + to force a new dependency to use the latest version of lodash via the + "resolutions" field in package.json. + + If you have questions about this please reach out to the operations team. + + `); + + process.exit(1); + } // look through all the dependencies of production packages and production + // dependencies of those packages to determine if we're shipping any versions + // of lodash v3 in the distributable const prodDependencies = osd.resolveAllProductionDependencies(yarnLock, _log.log); @@ -38190,7 +38621,7 @@ function getDevOnlyProductionDepsTree(osd, projectName) { } /***/ }), -/* 289 */ +/* 296 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38206,7 +38637,7 @@ var _chalk = _interopRequireDefault(__webpack_require__(113)); var _path = _interopRequireDefault(__webpack_require__(4)); -var _crossPlatform = __webpack_require__(290); +var _crossPlatform = __webpack_require__(288); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -38366,393 +38797,7 @@ function addProjectToTree(tree, pathParts, project) { } /***/ }), -/* 290 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -const tslib_1 = __webpack_require__(7); - -tslib_1.__exportStar(__webpack_require__(291), exports); - -tslib_1.__exportStar(__webpack_require__(292), exports); - -tslib_1.__exportStar(__webpack_require__(293), exports); - -/***/ }), -/* 291 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.realshortpathSync = exports.realShortPathSync = exports.realpathSync = exports.realPathSync = exports.resolveToShortNameSync = exports.resolveToShortPathSync = exports.resolveToFullNameSync = exports.resolveToFullPathSync = exports.shortNameSupportedSync = exports.shortNamesSupportedSync = exports.standardize = exports.NAMESPACE_PREFIX = void 0; - -const child_process_1 = __webpack_require__(238); - -const path_1 = __webpack_require__(4); - -const fs_1 = __webpack_require__(134); - -exports.NAMESPACE_PREFIX = process.platform === 'win32' ? '\\\\?\\' : ''; -/** - * Get a standardized reference to a path - * @param {string} path - the path to standardize - * @param {boolean} [usePosix=true] - produce a posix reference - * @param {boolean} [escapedBackslashes=true] - on Windows, double-backslash the reference - * @param {boolean} [returnUNC=false] - produce an extended reference - */ - -exports.standardize = (path, usePosix = true, escapedBackslashes = true, returnUNC = false) => { - var _process; - - // Force os-dependant separators - const normal = path_1.normalize(path); // Filter out in-browser executions as well as non-windows ones - - if (((_process = process) === null || _process === void 0 ? void 0 : _process.platform) !== 'win32') return normal; - if (usePosix) return normal.replace(/\\/g, '/');else if (escapedBackslashes) return normal.replace(/\\/g, '\\\\');else if (returnUNC) return '\\\\?\\' + normal; - return normal; -}; -/** - * Windows-only function that uses PowerShell to calculate the full path - * @param {string} path - * @private - */ - - -const getFullPathSync = path => { - if (process.platform !== 'win32') return path; - - try { - var _child_process_1$exec, _child_process_1$exec2; - - const fullName = (_child_process_1$exec = child_process_1.execSync(`powershell "(Get-Item -LiteralPath '${path}').FullName"`, { - encoding: 'utf8' - })) === null || _child_process_1$exec === void 0 ? void 0 : (_child_process_1$exec2 = _child_process_1$exec.trim) === null || _child_process_1$exec2 === void 0 ? void 0 : _child_process_1$exec2.call(_child_process_1$exec); // Make sure we got something back - - if ((fullName === null || fullName === void 0 ? void 0 : fullName.length) > 2) return fullName; - } catch (ex) {// Do nothing - } - - return path; -}; -/** - * Windows-only function that uses PowerShell and Com Object to calculate the 8.3 path - * @param {string} path - * @private - */ - - -const getShortPathSync = path => { - if (process.platform !== 'win32') return path; - - try { - var _child_process_1$exec3, _child_process_1$exec4; - - const shortPath = (_child_process_1$exec3 = child_process_1.execSync(`powershell "$FSO = New-Object -ComObject Scripting.FileSystemObject; $O = (Get-Item -LiteralPath '${path}'); if ($O.PSIsContainer) { $FSO.GetFolder($O.FullName).ShortPath } else { $FSO.GetFile($O.FullName).ShortPath }"`, { - encoding: 'utf8' - })) === null || _child_process_1$exec3 === void 0 ? void 0 : (_child_process_1$exec4 = _child_process_1$exec3.trim) === null || _child_process_1$exec4 === void 0 ? void 0 : _child_process_1$exec4.call(_child_process_1$exec3); // Make sure we got something back - - if ((shortPath === null || shortPath === void 0 ? void 0 : shortPath.length) > 2) return shortPath; - } catch (ex) {// Do nothing - } - - return path; -}; -/** - * Checks if Windows 8.3 short names are supported on the volume of the given path - * @param {string} [path='.'] - the path to examine - */ - - -exports.shortNamesSupportedSync = (path = '.') => { - if (process.platform !== 'win32') return false; - const testFileName = '.___osd-cross-platform-test.file'; - const file = path_1.resolve(path, testFileName); // Create a test file if it doesn't exist - - if (!fs_1.existsSync(file)) fs_1.closeSync(fs_1.openSync(file, 'w')); // If the returned value's basename is not the same as the requested file name, it must be a short name - - const foundShortName = path_1.basename(getShortPathSync(file)) !== testFileName; // Cleanup - - fs_1.unlinkSync(file); - return foundShortName; -}; -/** - * @borrows shortNamesSupportedSync - */ - - -exports.shortNameSupportedSync = exports.shortNamesSupportedSync; -/** - * Get the full pathname - * @param {string} path - the path to resolve - */ - -exports.resolveToFullPathSync = path => getFullPathSync(path_1.resolve(path)); -/** - * @borrows resolveToFullPathSync - */ - - -exports.resolveToFullNameSync = exports.resolveToFullPathSync; -/** - * Get the short pathname - * @param {string} path - the path to resolve - */ - -exports.resolveToShortPathSync = path => getShortPathSync(path_1.resolve(path)); -/** - * @borrows resolveToShortPathSync - */ - - -exports.resolveToShortNameSync = exports.resolveToShortPathSync; -/** - * Get the canonical pathname - * @param {string} path - the path to resolve - */ - -exports.realPathSync = path => getFullPathSync(fs_1.realpathSync(path, 'utf8')); -/** - * @borrows realPathSync - */ - - -exports.realpathSync = exports.realPathSync; -/** - * Get the canonical pathname - * @param {string} path - the path to resolve - */ - -exports.realShortPathSync = path => getShortPathSync(fs_1.realpathSync(path, 'utf8')); -/** - * @borrows realShortPathSync - */ - - -exports.realshortpathSync = exports.realShortPathSync; - -/***/ }), -/* 292 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.PROCESS_POSIX_WORKING_DIR = exports.PROCESS_WORKING_DIR = void 0; - -const path_1 = __webpack_require__(291); -/** - * The full pathname of the working directory of the process - * @constant - * @type {string} - */ - - -exports.PROCESS_WORKING_DIR = path_1.resolveToFullPathSync(process.cwd()); -/** - * The full pathname of the working directory of the process, in POSIX format - * @constant - * @type {string} - */ - -exports.PROCESS_POSIX_WORKING_DIR = path_1.standardize(exports.PROCESS_WORKING_DIR); - -/***/ }), -/* 293 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * 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. - */ - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.relativeToRepoRoot = exports.getRepoRoot = exports.getMatchingRoot = exports.UPSTREAM_BRANCH = exports.REPO_ROOT_8_3 = exports.REPO_ROOT = void 0; - -const tslib_1 = __webpack_require__(7); -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -const path_1 = __webpack_require__(4); - -const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(294)); - -const path_2 = __webpack_require__(291); - -const readOpenSearchDashboardsPkgJson = dir => { - try { - const path = path_1.resolve(dir, 'package.json'); - const json = load_json_file_1.default.sync(path); - - if ((json === null || json === void 0 ? void 0 : json.name) === 'opensearch-dashboards') { - return json; - } - } catch (error) { - if (error && error.code === 'ENOENT') { - return; - } - - throw error; - } -}; - -const findOpenSearchDashboardsPackageJson = () => { - // search for the opensearch-dashboards directory, since this file is moved around it might - // not be where we think but should always be a relatively close parent - // of this directory - const startDir = path_2.realPathSync(__dirname); - const { - root: rootDir - } = path_1.parse(startDir); - let cursor = startDir; - - while (true) { - const opensearchDashboardsPkgJson = readOpenSearchDashboardsPkgJson(cursor); - - if (opensearchDashboardsPkgJson) { - return { - opensearchDashboardsDir: cursor, - opensearchDashboardsPkgJson: opensearchDashboardsPkgJson - }; - } - - const parent = path_1.dirname(cursor); - - if (parent === rootDir) { - throw new Error(`unable to find opensearch-dashboards directory from ${startDir}`); - } - - cursor = parent; - } -}; - -const { - opensearchDashboardsDir, - opensearchDashboardsPkgJson -} = findOpenSearchDashboardsPackageJson(); -exports.REPO_ROOT = path_2.resolveToFullPathSync(opensearchDashboardsDir); -exports.REPO_ROOT_8_3 = path_2.resolveToShortPathSync(opensearchDashboardsDir); -exports.UPSTREAM_BRANCH = opensearchDashboardsPkgJson.branch; - -exports.getMatchingRoot = (path, rootPaths) => { - const rootPathsArray = Array.isArray(rootPaths) ? rootPaths : [rootPaths]; // We can only find the appropriate root if an absolute path was given - - if (path && path_1.isAbsolute(path)) { - // Return the matching root if one is found or return `undefined` - return rootPathsArray.find(root => path.startsWith(root)); - } - - return undefined; -}; - -exports.getRepoRoot = path => exports.getMatchingRoot(path, [exports.REPO_ROOT, exports.REPO_ROOT_8_3]); - -exports.relativeToRepoRoot = path => { - const repoRoot = exports.getRepoRoot(path); - return repoRoot ? path_1.relative(repoRoot, path) : null; -}; - -/***/ }), -/* 294 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(4); -const {promisify} = __webpack_require__(112); -const fs = __webpack_require__(133); -const stripBom = __webpack_require__(295); -const parseJson = __webpack_require__(167); - -const parse = (data, filePath, options = {}) => { - data = stripBom(data); - - if (typeof options.beforeParse === 'function') { - data = options.beforeParse(data); - } - - return parseJson(data, options.reviver, path.relative(process.cwd(), filePath)); -}; - -module.exports = async (filePath, options) => parse(await promisify(fs.readFile)(filePath, 'utf8'), filePath, options); -module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'utf8'), filePath, options); - - -/***/ }), -/* 295 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = string => { - if (typeof string !== 'string') { - throw new TypeError(`Expected a string, got ${typeof string}`); - } - - // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string - // conversion translates it to FEFF (UTF-16 BOM) - if (string.charCodeAt(0) === 0xFEFF) { - return string.slice(1); - } - - return string; -}; - - -/***/ }), -/* 296 */ +/* 297 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38763,15 +38808,15 @@ Object.defineProperty(exports, "__esModule", { }); exports.CleanCommand = void 0; -var _del = _interopRequireDefault(__webpack_require__(297)); +var _del = _interopRequireDefault(__webpack_require__(298)); -var _ora = _interopRequireDefault(__webpack_require__(386)); +var _ora = _interopRequireDefault(__webpack_require__(387)); var _path = __webpack_require__(4); var _fs = __webpack_require__(131); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -38876,21 +38921,21 @@ const CleanCommand = { exports.CleanCommand = CleanCommand; /***/ }), -/* 297 */ +/* 298 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(112); const path = __webpack_require__(4); -const globby = __webpack_require__(298); -const isGlob = __webpack_require__(310); -const slash = __webpack_require__(377); +const globby = __webpack_require__(299); +const isGlob = __webpack_require__(311); +const slash = __webpack_require__(378); const gracefulFs = __webpack_require__(133); -const isPathCwd = __webpack_require__(379); -const isPathInside = __webpack_require__(380); -const rimraf = __webpack_require__(381); -const pMap = __webpack_require__(382); +const isPathCwd = __webpack_require__(380); +const isPathInside = __webpack_require__(381); +const rimraf = __webpack_require__(382); +const pMap = __webpack_require__(383); const rimrafP = promisify(rimraf); @@ -39022,18 +39067,18 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options /***/ }), -/* 298 */ +/* 299 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const arrayUnion = __webpack_require__(299); -const merge2 = __webpack_require__(300); -const fastGlob = __webpack_require__(301); -const dirGlob = __webpack_require__(373); -const gitignore = __webpack_require__(375); -const {FilterStream, UniqueStream} = __webpack_require__(378); +const arrayUnion = __webpack_require__(300); +const merge2 = __webpack_require__(301); +const fastGlob = __webpack_require__(302); +const dirGlob = __webpack_require__(374); +const gitignore = __webpack_require__(376); +const {FilterStream, UniqueStream} = __webpack_require__(379); const DEFAULT_FILTER = () => false; @@ -39210,7 +39255,7 @@ module.exports.gitignore = gitignore; /***/ }), -/* 299 */ +/* 300 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39222,7 +39267,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 300 */ +/* 301 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39373,18 +39418,18 @@ function pauseStreams (streams, options) { /***/ }), -/* 301 */ +/* 302 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const taskManager = __webpack_require__(302); -const patternManager = __webpack_require__(331); -const async_1 = __webpack_require__(332); -const stream_1 = __webpack_require__(369); -const sync_1 = __webpack_require__(370); -const settings_1 = __webpack_require__(372); -const utils = __webpack_require__(303); +const taskManager = __webpack_require__(303); +const patternManager = __webpack_require__(332); +const async_1 = __webpack_require__(333); +const stream_1 = __webpack_require__(370); +const sync_1 = __webpack_require__(371); +const settings_1 = __webpack_require__(373); +const utils = __webpack_require__(304); async function FastGlob(source, options) { assertPatternsInput(source); const works = getWorks(source, async_1.default, options); @@ -39448,14 +39493,14 @@ module.exports = FastGlob; /***/ }), -/* 302 */ +/* 303 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertPatternGroupToTask = exports.convertPatternGroupsToTasks = exports.groupPatternsByBaseDirectory = exports.getNegativePatternsAsPositive = exports.getPositivePatterns = exports.convertPatternsToTasks = exports.generate = void 0; -const utils = __webpack_require__(303); +const utils = __webpack_require__(304); function generate(patterns, settings) { const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); @@ -39535,31 +39580,31 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 303 */ +/* 304 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.string = exports.stream = exports.pattern = exports.path = exports.fs = exports.errno = exports.array = void 0; -const array = __webpack_require__(304); +const array = __webpack_require__(305); exports.array = array; -const errno = __webpack_require__(305); +const errno = __webpack_require__(306); exports.errno = errno; -const fs = __webpack_require__(306); +const fs = __webpack_require__(307); exports.fs = fs; -const path = __webpack_require__(307); +const path = __webpack_require__(308); exports.path = path; -const pattern = __webpack_require__(308); +const pattern = __webpack_require__(309); exports.pattern = pattern; -const stream = __webpack_require__(329); +const stream = __webpack_require__(330); exports.stream = stream; -const string = __webpack_require__(330); +const string = __webpack_require__(331); exports.string = string; /***/ }), -/* 304 */ +/* 305 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39588,7 +39633,7 @@ exports.splitWhen = splitWhen; /***/ }), -/* 305 */ +/* 306 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39602,7 +39647,7 @@ exports.isEnoentCodeError = isEnoentCodeError; /***/ }), -/* 306 */ +/* 307 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39628,7 +39673,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 307 */ +/* 308 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39668,7 +39713,7 @@ exports.removeLeadingDotSegment = removeLeadingDotSegment; /***/ }), -/* 308 */ +/* 309 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -39676,8 +39721,8 @@ exports.removeLeadingDotSegment = removeLeadingDotSegment; Object.defineProperty(exports, "__esModule", { value: true }); exports.matchAny = exports.convertPatternsToRe = exports.makeRe = exports.getPatternParts = exports.expandBraceExpansion = exports.expandPatternsWithBraceExpansion = exports.isAffectDepthOfReadingPattern = exports.endsWithSlashGlobStar = exports.hasGlobStar = exports.getBaseDirectory = exports.isPatternRelatedToParentDirectory = exports.getPatternsOutsideCurrentDirectory = exports.getPatternsInsideCurrentDirectory = exports.getPositivePatterns = exports.getNegativePatterns = exports.isPositivePattern = exports.isNegativePattern = exports.convertToNegativePattern = exports.convertToPositivePattern = exports.isDynamicPattern = exports.isStaticPattern = void 0; const path = __webpack_require__(4); -const globParent = __webpack_require__(309); -const micromatch = __webpack_require__(312); +const globParent = __webpack_require__(310); +const micromatch = __webpack_require__(313); const GLOBSTAR = '**'; const ESCAPE_SYMBOL = '\\'; const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/; @@ -39844,13 +39889,13 @@ exports.matchAny = matchAny; /***/ }), -/* 309 */ +/* 310 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isGlob = __webpack_require__(310); +var isGlob = __webpack_require__(311); var pathPosixDirname = __webpack_require__(4).posix.dirname; var isWin32 = __webpack_require__(121).platform() === 'win32'; @@ -39926,7 +39971,7 @@ function isGlobby(str) { /***/ }), -/* 310 */ +/* 311 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -39936,7 +39981,7 @@ function isGlobby(str) { * Released under the MIT License. */ -var isExtglob = __webpack_require__(311); +var isExtglob = __webpack_require__(312); var chars = { '{': '}', '(': ')', '[': ']'}; var strictCheck = function(str) { if (str[0] === '!') { @@ -40082,7 +40127,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 311 */ +/* 312 */ /***/ (function(module, exports) { /*! @@ -40108,16 +40153,16 @@ module.exports = function isExtglob(str) { /***/ }), -/* 312 */ +/* 313 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const util = __webpack_require__(112); -const braces = __webpack_require__(313); -const picomatch = __webpack_require__(323); -const utils = __webpack_require__(326); +const braces = __webpack_require__(314); +const picomatch = __webpack_require__(324); +const utils = __webpack_require__(327); const isEmptyString = val => val === '' || val === './'; /** @@ -40582,16 +40627,16 @@ module.exports = micromatch; /***/ }), -/* 313 */ +/* 314 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(314); -const compile = __webpack_require__(316); -const expand = __webpack_require__(320); -const parse = __webpack_require__(321); +const stringify = __webpack_require__(315); +const compile = __webpack_require__(317); +const expand = __webpack_require__(321); +const parse = __webpack_require__(322); /** * Expand the given pattern or create a regex-compatible string. @@ -40759,13 +40804,13 @@ module.exports = braces; /***/ }), -/* 314 */ +/* 315 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(315); +const utils = __webpack_require__(316); module.exports = (ast, options = {}) => { let stringify = (node, parent = {}) => { @@ -40798,7 +40843,7 @@ module.exports = (ast, options = {}) => { /***/ }), -/* 315 */ +/* 316 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40917,14 +40962,14 @@ exports.flatten = (...args) => { /***/ }), -/* 316 */ +/* 317 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(317); -const utils = __webpack_require__(315); +const fill = __webpack_require__(318); +const utils = __webpack_require__(316); const compile = (ast, options = {}) => { let walk = (node, parent = {}) => { @@ -40981,7 +41026,7 @@ module.exports = compile; /***/ }), -/* 317 */ +/* 318 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40995,7 +41040,7 @@ module.exports = compile; const util = __webpack_require__(112); -const toRegexRange = __webpack_require__(318); +const toRegexRange = __webpack_require__(319); const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); @@ -41237,7 +41282,7 @@ module.exports = fill; /***/ }), -/* 318 */ +/* 319 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41250,7 +41295,7 @@ module.exports = fill; -const isNumber = __webpack_require__(319); +const isNumber = __webpack_require__(320); const toRegexRange = (min, max, options) => { if (isNumber(min) === false) { @@ -41532,7 +41577,7 @@ module.exports = toRegexRange; /***/ }), -/* 319 */ +/* 320 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41557,15 +41602,15 @@ module.exports = function(num) { /***/ }), -/* 320 */ +/* 321 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(317); -const stringify = __webpack_require__(314); -const utils = __webpack_require__(315); +const fill = __webpack_require__(318); +const stringify = __webpack_require__(315); +const utils = __webpack_require__(316); const append = (queue = '', stash = '', enclose = false) => { let result = []; @@ -41677,13 +41722,13 @@ module.exports = expand; /***/ }), -/* 321 */ +/* 322 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(314); +const stringify = __webpack_require__(315); /** * Constants @@ -41705,7 +41750,7 @@ const { CHAR_SINGLE_QUOTE, /* ' */ CHAR_NO_BREAK_SPACE, CHAR_ZERO_WIDTH_NOBREAK_SPACE -} = __webpack_require__(322); +} = __webpack_require__(323); /** * parse @@ -42017,7 +42062,7 @@ module.exports = parse; /***/ }), -/* 322 */ +/* 323 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -42081,27 +42126,27 @@ module.exports = { /***/ }), -/* 323 */ +/* 324 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(324); +module.exports = __webpack_require__(325); /***/ }), -/* 324 */ +/* 325 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const scan = __webpack_require__(325); -const parse = __webpack_require__(328); -const utils = __webpack_require__(326); -const constants = __webpack_require__(327); +const scan = __webpack_require__(326); +const parse = __webpack_require__(329); +const utils = __webpack_require__(327); +const constants = __webpack_require__(328); const isObject = val => val && typeof val === 'object' && !Array.isArray(val); /** @@ -42440,13 +42485,13 @@ module.exports = picomatch; /***/ }), -/* 325 */ +/* 326 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(326); +const utils = __webpack_require__(327); const { CHAR_ASTERISK, /* * */ CHAR_AT, /* @ */ @@ -42463,7 +42508,7 @@ const { CHAR_RIGHT_CURLY_BRACE, /* } */ CHAR_RIGHT_PARENTHESES, /* ) */ CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(327); +} = __webpack_require__(328); const isPathSeparator = code => { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; @@ -42838,7 +42883,7 @@ module.exports = scan; /***/ }), -/* 326 */ +/* 327 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -42851,7 +42896,7 @@ const { REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL -} = __webpack_require__(327); +} = __webpack_require__(328); exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); @@ -42909,7 +42954,7 @@ exports.wrapOutput = (input, state = {}, options = {}) => { /***/ }), -/* 327 */ +/* 328 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43095,14 +43140,14 @@ module.exports = { /***/ }), -/* 328 */ +/* 329 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const constants = __webpack_require__(327); -const utils = __webpack_require__(326); +const constants = __webpack_require__(328); +const utils = __webpack_require__(327); /** * Constants @@ -44193,14 +44238,14 @@ module.exports = parse; /***/ }), -/* 329 */ +/* 330 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.merge = void 0; -const merge2 = __webpack_require__(300); +const merge2 = __webpack_require__(301); function merge(streams) { const mergedStream = merge2(streams); streams.forEach((stream) => { @@ -44217,7 +44262,7 @@ function propagateCloseEventToSources(streams) { /***/ }), -/* 330 */ +/* 331 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44235,7 +44280,7 @@ exports.isEmpty = isEmpty; /***/ }), -/* 331 */ +/* 332 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44263,14 +44308,14 @@ exports.removeDuplicateSlashes = removeDuplicateSlashes; /***/ }), -/* 332 */ +/* 333 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(333); -const provider_1 = __webpack_require__(362); +const stream_1 = __webpack_require__(334); +const provider_1 = __webpack_require__(363); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); @@ -44298,16 +44343,16 @@ exports.default = ProviderAsync; /***/ }), -/* 333 */ +/* 334 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(138); -const fsStat = __webpack_require__(334); -const fsWalk = __webpack_require__(339); -const reader_1 = __webpack_require__(361); +const fsStat = __webpack_require__(335); +const fsWalk = __webpack_require__(340); +const reader_1 = __webpack_require__(362); class ReaderStream extends reader_1.default { constructor() { super(...arguments); @@ -44360,16 +44405,16 @@ exports.default = ReaderStream; /***/ }), -/* 334 */ +/* 335 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.statSync = exports.stat = exports.Settings = void 0; -const async = __webpack_require__(335); -const sync = __webpack_require__(336); -const settings_1 = __webpack_require__(337); +const async = __webpack_require__(336); +const sync = __webpack_require__(337); +const settings_1 = __webpack_require__(338); exports.Settings = settings_1.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -44393,7 +44438,7 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 335 */ +/* 336 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44436,7 +44481,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 336 */ +/* 337 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44466,13 +44511,13 @@ exports.read = read; /***/ }), -/* 337 */ +/* 338 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(338); +const fs = __webpack_require__(339); class Settings { constructor(_options = {}) { this._options = _options; @@ -44489,7 +44534,7 @@ exports.default = Settings; /***/ }), -/* 338 */ +/* 339 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44513,17 +44558,17 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 339 */ +/* 340 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Settings = exports.walkStream = exports.walkSync = exports.walk = void 0; -const async_1 = __webpack_require__(340); -const stream_1 = __webpack_require__(357); -const sync_1 = __webpack_require__(358); -const settings_1 = __webpack_require__(360); +const async_1 = __webpack_require__(341); +const stream_1 = __webpack_require__(358); +const sync_1 = __webpack_require__(359); +const settings_1 = __webpack_require__(361); exports.Settings = settings_1.default; function walk(directory, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -44554,13 +44599,13 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 340 */ +/* 341 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(341); +const async_1 = __webpack_require__(342); class AsyncProvider { constructor(_root, _settings) { this._root = _root; @@ -44591,17 +44636,17 @@ function callSuccessCallback(callback, entries) { /***/ }), -/* 341 */ +/* 342 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const events_1 = __webpack_require__(156); -const fsScandir = __webpack_require__(342); -const fastq = __webpack_require__(353); -const common = __webpack_require__(355); -const reader_1 = __webpack_require__(356); +const events_1 = __webpack_require__(157); +const fsScandir = __webpack_require__(343); +const fastq = __webpack_require__(354); +const common = __webpack_require__(356); +const reader_1 = __webpack_require__(357); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); @@ -44695,16 +44740,16 @@ exports.default = AsyncReader; /***/ }), -/* 342 */ +/* 343 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Settings = exports.scandirSync = exports.scandir = void 0; -const async = __webpack_require__(343); -const sync = __webpack_require__(350); -const settings_1 = __webpack_require__(351); +const async = __webpack_require__(344); +const sync = __webpack_require__(351); +const settings_1 = __webpack_require__(352); exports.Settings = settings_1.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -44728,18 +44773,18 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 343 */ +/* 344 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readdir = exports.readdirWithFileTypes = exports.read = void 0; -const fsStat = __webpack_require__(334); -const rpl = __webpack_require__(344); -const constants_1 = __webpack_require__(346); -const utils = __webpack_require__(347); -const common = __webpack_require__(349); +const fsStat = __webpack_require__(335); +const rpl = __webpack_require__(345); +const constants_1 = __webpack_require__(347); +const utils = __webpack_require__(348); +const common = __webpack_require__(350); function read(directory, settings, callback) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { readdirWithFileTypes(directory, settings, callback); @@ -44839,13 +44884,13 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 344 */ +/* 345 */ /***/ (function(module, exports, __webpack_require__) { /*! run-parallel. MIT License. Feross Aboukhadijeh */ module.exports = runParallel -const queueMicrotask = __webpack_require__(345) +const queueMicrotask = __webpack_require__(346) function runParallel (tasks, cb) { let results, pending, keys @@ -44896,7 +44941,7 @@ function runParallel (tasks, cb) { /***/ }), -/* 345 */ +/* 346 */ /***/ (function(module, exports) { /*! queue-microtask. MIT License. Feross Aboukhadijeh */ @@ -44911,7 +44956,7 @@ module.exports = typeof queueMicrotask === 'function' /***/ }), -/* 346 */ +/* 347 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44935,19 +44980,19 @@ exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = IS_MATCHED_BY_MAJOR || IS_MATCHED_B /***/ }), -/* 347 */ +/* 348 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fs = void 0; -const fs = __webpack_require__(348); +const fs = __webpack_require__(349); exports.fs = fs; /***/ }), -/* 348 */ +/* 349 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44973,7 +45018,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 349 */ +/* 350 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -44993,17 +45038,17 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 350 */ +/* 351 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readdir = exports.readdirWithFileTypes = exports.read = void 0; -const fsStat = __webpack_require__(334); -const constants_1 = __webpack_require__(346); -const utils = __webpack_require__(347); -const common = __webpack_require__(349); +const fsStat = __webpack_require__(335); +const constants_1 = __webpack_require__(347); +const utils = __webpack_require__(348); +const common = __webpack_require__(350); function read(directory, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(directory, settings); @@ -45054,15 +45099,15 @@ exports.readdir = readdir; /***/ }), -/* 351 */ +/* 352 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsStat = __webpack_require__(334); -const fs = __webpack_require__(352); +const fsStat = __webpack_require__(335); +const fs = __webpack_require__(353); class Settings { constructor(_options = {}) { this._options = _options; @@ -45085,7 +45130,7 @@ exports.default = Settings; /***/ }), -/* 352 */ +/* 353 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45111,7 +45156,7 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 353 */ +/* 354 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45119,7 +45164,7 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /* eslint-disable no-var */ -var reusify = __webpack_require__(354) +var reusify = __webpack_require__(355) function fastqueue (context, worker, concurrency) { if (typeof context === 'function') { @@ -45401,7 +45446,7 @@ module.exports.promise = queueAsPromised /***/ }), -/* 354 */ +/* 355 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45441,7 +45486,7 @@ module.exports = reusify /***/ }), -/* 355 */ +/* 356 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -45479,13 +45524,13 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 356 */ +/* 357 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(355); +const common = __webpack_require__(356); class Reader { constructor(_root, _settings) { this._root = _root; @@ -45497,14 +45542,14 @@ exports.default = Reader; /***/ }), -/* 357 */ +/* 358 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(138); -const async_1 = __webpack_require__(341); +const async_1 = __webpack_require__(342); class StreamProvider { constructor(_root, _settings) { this._root = _root; @@ -45538,13 +45583,13 @@ exports.default = StreamProvider; /***/ }), -/* 358 */ +/* 359 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(359); +const sync_1 = __webpack_require__(360); class SyncProvider { constructor(_root, _settings) { this._root = _root; @@ -45559,15 +45604,15 @@ exports.default = SyncProvider; /***/ }), -/* 359 */ +/* 360 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(342); -const common = __webpack_require__(355); -const reader_1 = __webpack_require__(356); +const fsScandir = __webpack_require__(343); +const common = __webpack_require__(356); +const reader_1 = __webpack_require__(357); class SyncReader extends reader_1.default { constructor() { super(...arguments); @@ -45625,14 +45670,14 @@ exports.default = SyncReader; /***/ }), -/* 360 */ +/* 361 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsScandir = __webpack_require__(342); +const fsScandir = __webpack_require__(343); class Settings { constructor(_options = {}) { this._options = _options; @@ -45658,15 +45703,15 @@ exports.default = Settings; /***/ }), -/* 361 */ +/* 362 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const fsStat = __webpack_require__(334); -const utils = __webpack_require__(303); +const fsStat = __webpack_require__(335); +const utils = __webpack_require__(304); class Reader { constructor(_settings) { this._settings = _settings; @@ -45698,17 +45743,17 @@ exports.default = Reader; /***/ }), -/* 362 */ +/* 363 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const deep_1 = __webpack_require__(363); -const entry_1 = __webpack_require__(366); -const error_1 = __webpack_require__(367); -const entry_2 = __webpack_require__(368); +const deep_1 = __webpack_require__(364); +const entry_1 = __webpack_require__(367); +const error_1 = __webpack_require__(368); +const entry_2 = __webpack_require__(369); class Provider { constructor(_settings) { this._settings = _settings; @@ -45753,14 +45798,14 @@ exports.default = Provider; /***/ }), -/* 363 */ +/* 364 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(303); -const partial_1 = __webpack_require__(364); +const utils = __webpack_require__(304); +const partial_1 = __webpack_require__(365); class DeepFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -45822,13 +45867,13 @@ exports.default = DeepFilter; /***/ }), -/* 364 */ +/* 365 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const matcher_1 = __webpack_require__(365); +const matcher_1 = __webpack_require__(366); class PartialMatcher extends matcher_1.default { match(filepath) { const parts = filepath.split('/'); @@ -45867,13 +45912,13 @@ exports.default = PartialMatcher; /***/ }), -/* 365 */ +/* 366 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(303); +const utils = __webpack_require__(304); class Matcher { constructor(_patterns, _settings, _micromatchOptions) { this._patterns = _patterns; @@ -45924,13 +45969,13 @@ exports.default = Matcher; /***/ }), -/* 366 */ +/* 367 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(303); +const utils = __webpack_require__(304); class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -45991,13 +46036,13 @@ exports.default = EntryFilter; /***/ }), -/* 367 */ +/* 368 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(303); +const utils = __webpack_require__(304); class ErrorFilter { constructor(_settings) { this._settings = _settings; @@ -46013,13 +46058,13 @@ exports.default = ErrorFilter; /***/ }), -/* 368 */ +/* 369 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(303); +const utils = __webpack_require__(304); class EntryTransformer { constructor(_settings) { this._settings = _settings; @@ -46046,15 +46091,15 @@ exports.default = EntryTransformer; /***/ }), -/* 369 */ +/* 370 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(138); -const stream_2 = __webpack_require__(333); -const provider_1 = __webpack_require__(362); +const stream_2 = __webpack_require__(334); +const provider_1 = __webpack_require__(363); class ProviderStream extends provider_1.default { constructor() { super(...arguments); @@ -46084,14 +46129,14 @@ exports.default = ProviderStream; /***/ }), -/* 370 */ +/* 371 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(371); -const provider_1 = __webpack_require__(362); +const sync_1 = __webpack_require__(372); +const provider_1 = __webpack_require__(363); class ProviderSync extends provider_1.default { constructor() { super(...arguments); @@ -46114,15 +46159,15 @@ exports.default = ProviderSync; /***/ }), -/* 371 */ +/* 372 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(334); -const fsWalk = __webpack_require__(339); -const reader_1 = __webpack_require__(361); +const fsStat = __webpack_require__(335); +const fsWalk = __webpack_require__(340); +const reader_1 = __webpack_require__(362); class ReaderSync extends reader_1.default { constructor() { super(...arguments); @@ -46164,7 +46209,7 @@ exports.default = ReaderSync; /***/ }), -/* 372 */ +/* 373 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46228,13 +46273,13 @@ exports.default = Settings; /***/ }), -/* 373 */ +/* 374 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(374); +const pathType = __webpack_require__(375); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -46310,7 +46355,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 374 */ +/* 375 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46360,7 +46405,7 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 375 */ +/* 376 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46368,9 +46413,9 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); const {promisify} = __webpack_require__(112); const fs = __webpack_require__(134); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(301); -const gitIgnore = __webpack_require__(376); -const slash = __webpack_require__(377); +const fastGlob = __webpack_require__(302); +const gitIgnore = __webpack_require__(377); +const slash = __webpack_require__(378); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -46487,7 +46532,7 @@ module.exports.sync = options => { /***/ }), -/* 376 */ +/* 377 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -47096,7 +47141,7 @@ if ( /***/ }), -/* 377 */ +/* 378 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47114,7 +47159,7 @@ module.exports = path => { /***/ }), -/* 378 */ +/* 379 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47167,7 +47212,7 @@ module.exports = { /***/ }), -/* 379 */ +/* 380 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47189,7 +47234,7 @@ module.exports = path_ => { /***/ }), -/* 380 */ +/* 381 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47208,7 +47253,7 @@ module.exports = (childPath, parentPath) => { /***/ }), -/* 381 */ +/* 382 */ /***/ (function(module, exports, __webpack_require__) { const assert = __webpack_require__(140) @@ -47216,7 +47261,7 @@ const path = __webpack_require__(4) const fs = __webpack_require__(134) let glob = undefined try { - glob = __webpack_require__(147) + glob = __webpack_require__(148) } catch (_err) { // treat glob as optional. } @@ -47574,12 +47619,12 @@ rimraf.sync = rimrafSync /***/ }), -/* 382 */ +/* 383 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(383); +const AggregateError = __webpack_require__(384); module.exports = async ( iterable, @@ -47662,13 +47707,13 @@ module.exports = async ( /***/ }), -/* 383 */ +/* 384 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(384); -const cleanStack = __webpack_require__(385); +const indentString = __webpack_require__(385); +const cleanStack = __webpack_require__(386); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -47716,7 +47761,7 @@ module.exports = AggregateError; /***/ }), -/* 384 */ +/* 385 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47758,7 +47803,7 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 385 */ +/* 386 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47805,20 +47850,20 @@ module.exports = (stack, options) => { /***/ }), -/* 386 */ +/* 387 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readline = __webpack_require__(387); -const chalk = __webpack_require__(388); -const cliCursor = __webpack_require__(391); -const cliSpinners = __webpack_require__(393); -const logSymbols = __webpack_require__(395); -const stripAnsi = __webpack_require__(401); -const wcwidth = __webpack_require__(403); -const isInteractive = __webpack_require__(407); -const MuteStream = __webpack_require__(408); +const readline = __webpack_require__(388); +const chalk = __webpack_require__(389); +const cliCursor = __webpack_require__(392); +const cliSpinners = __webpack_require__(394); +const logSymbols = __webpack_require__(396); +const stripAnsi = __webpack_require__(402); +const wcwidth = __webpack_require__(404); +const isInteractive = __webpack_require__(408); +const MuteStream = __webpack_require__(409); const TEXT = Symbol('text'); const PREFIX_TEXT = Symbol('prefixText'); @@ -48171,13 +48216,13 @@ module.exports.promise = (action, options) => { /***/ }), -/* 387 */ +/* 388 */ /***/ (function(module, exports) { module.exports = require("readline"); /***/ }), -/* 388 */ +/* 389 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48187,7 +48232,7 @@ const {stdout: stdoutColor, stderr: stderrColor} = __webpack_require__(120); const { stringReplaceAll, stringEncaseCRLFWithFirstIndex -} = __webpack_require__(389); +} = __webpack_require__(390); // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ @@ -48388,7 +48433,7 @@ const chalkTag = (chalk, ...strings) => { } if (template === undefined) { - template = __webpack_require__(390); + template = __webpack_require__(391); } return template(chalk, parts.join('')); @@ -48417,7 +48462,7 @@ module.exports = chalk; /***/ }), -/* 389 */ +/* 390 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48463,7 +48508,7 @@ module.exports = { /***/ }), -/* 390 */ +/* 391 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -48604,12 +48649,12 @@ module.exports = (chalk, temporary) => { /***/ }), -/* 391 */ +/* 392 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(392); +const restoreCursor = __webpack_require__(393); let isHidden = false; @@ -48646,13 +48691,13 @@ exports.toggle = (force, writableStream) => { /***/ }), -/* 392 */ +/* 393 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(254); -const signalExit = __webpack_require__(227); +const onetime = __webpack_require__(255); +const signalExit = __webpack_require__(228); module.exports = onetime(() => { signalExit(() => { @@ -48662,13 +48707,13 @@ module.exports = onetime(() => { /***/ }), -/* 393 */ +/* 394 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const spinners = Object.assign({}, __webpack_require__(394)); // eslint-disable-line import/extensions +const spinners = Object.assign({}, __webpack_require__(395)); // eslint-disable-line import/extensions const spinnersList = Object.keys(spinners); @@ -48684,18 +48729,18 @@ module.exports = spinners; /***/ }), -/* 394 */ +/* 395 */ /***/ (function(module) { module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"dots8Bit\":{\"interval\":80,\"frames\":[\"⠀\",\"⠁\",\"⠂\",\"⠃\",\"⠄\",\"⠅\",\"⠆\",\"⠇\",\"⡀\",\"⡁\",\"⡂\",\"⡃\",\"⡄\",\"⡅\",\"⡆\",\"⡇\",\"⠈\",\"⠉\",\"⠊\",\"⠋\",\"⠌\",\"⠍\",\"⠎\",\"⠏\",\"⡈\",\"⡉\",\"⡊\",\"⡋\",\"⡌\",\"⡍\",\"⡎\",\"⡏\",\"⠐\",\"⠑\",\"⠒\",\"⠓\",\"⠔\",\"⠕\",\"⠖\",\"⠗\",\"⡐\",\"⡑\",\"⡒\",\"⡓\",\"⡔\",\"⡕\",\"⡖\",\"⡗\",\"⠘\",\"⠙\",\"⠚\",\"⠛\",\"⠜\",\"⠝\",\"⠞\",\"⠟\",\"⡘\",\"⡙\",\"⡚\",\"⡛\",\"⡜\",\"⡝\",\"⡞\",\"⡟\",\"⠠\",\"⠡\",\"⠢\",\"⠣\",\"⠤\",\"⠥\",\"⠦\",\"⠧\",\"⡠\",\"⡡\",\"⡢\",\"⡣\",\"⡤\",\"⡥\",\"⡦\",\"⡧\",\"⠨\",\"⠩\",\"⠪\",\"⠫\",\"⠬\",\"⠭\",\"⠮\",\"⠯\",\"⡨\",\"⡩\",\"⡪\",\"⡫\",\"⡬\",\"⡭\",\"⡮\",\"⡯\",\"⠰\",\"⠱\",\"⠲\",\"⠳\",\"⠴\",\"⠵\",\"⠶\",\"⠷\",\"⡰\",\"⡱\",\"⡲\",\"⡳\",\"⡴\",\"⡵\",\"⡶\",\"⡷\",\"⠸\",\"⠹\",\"⠺\",\"⠻\",\"⠼\",\"⠽\",\"⠾\",\"⠿\",\"⡸\",\"⡹\",\"⡺\",\"⡻\",\"⡼\",\"⡽\",\"⡾\",\"⡿\",\"⢀\",\"⢁\",\"⢂\",\"⢃\",\"⢄\",\"⢅\",\"⢆\",\"⢇\",\"⣀\",\"⣁\",\"⣂\",\"⣃\",\"⣄\",\"⣅\",\"⣆\",\"⣇\",\"⢈\",\"⢉\",\"⢊\",\"⢋\",\"⢌\",\"⢍\",\"⢎\",\"⢏\",\"⣈\",\"⣉\",\"⣊\",\"⣋\",\"⣌\",\"⣍\",\"⣎\",\"⣏\",\"⢐\",\"⢑\",\"⢒\",\"⢓\",\"⢔\",\"⢕\",\"⢖\",\"⢗\",\"⣐\",\"⣑\",\"⣒\",\"⣓\",\"⣔\",\"⣕\",\"⣖\",\"⣗\",\"⢘\",\"⢙\",\"⢚\",\"⢛\",\"⢜\",\"⢝\",\"⢞\",\"⢟\",\"⣘\",\"⣙\",\"⣚\",\"⣛\",\"⣜\",\"⣝\",\"⣞\",\"⣟\",\"⢠\",\"⢡\",\"⢢\",\"⢣\",\"⢤\",\"⢥\",\"⢦\",\"⢧\",\"⣠\",\"⣡\",\"⣢\",\"⣣\",\"⣤\",\"⣥\",\"⣦\",\"⣧\",\"⢨\",\"⢩\",\"⢪\",\"⢫\",\"⢬\",\"⢭\",\"⢮\",\"⢯\",\"⣨\",\"⣩\",\"⣪\",\"⣫\",\"⣬\",\"⣭\",\"⣮\",\"⣯\",\"⢰\",\"⢱\",\"⢲\",\"⢳\",\"⢴\",\"⢵\",\"⢶\",\"⢷\",\"⣰\",\"⣱\",\"⣲\",\"⣳\",\"⣴\",\"⣵\",\"⣶\",\"⣷\",\"⢸\",\"⢹\",\"⢺\",\"⢻\",\"⢼\",\"⢽\",\"⢾\",\"⢿\",\"⣸\",\"⣹\",\"⣺\",\"⣻\",\"⣼\",\"⣽\",\"⣾\",\"⣿\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕛 \",\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"material\":{\"interval\":17,\"frames\":[\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███████▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"██████████▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"█████████████▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁██████████████▁▁▁▁\",\"▁▁▁██████████████▁▁▁\",\"▁▁▁▁█████████████▁▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁▁█████████████▁▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁▁███████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁▁█████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]},\"grenade\":{\"interval\":80,\"frames\":[\"، \",\"′ \",\" ´ \",\" ‾ \",\" ⸌\",\" ⸊\",\" |\",\" ⁎\",\" ⁕\",\" ෴ \",\" ⁓\",\" \",\" \",\" \"]},\"point\":{\"interval\":125,\"frames\":[\"∙∙∙\",\"●∙∙\",\"∙●∙\",\"∙∙●\",\"∙∙∙\"]},\"layer\":{\"interval\":150,\"frames\":[\"-\",\"=\",\"≡\"]},\"betaWave\":{\"interval\":80,\"frames\":[\"ρββββββ\",\"βρβββββ\",\"ββρββββ\",\"βββρβββ\",\"ββββρββ\",\"βββββρβ\",\"ββββββρ\"]},\"fingerDance\":{\"interval\":160,\"frames\":[\"🤘 \",\"🤟 \",\"🖖 \",\"✋ \",\"🤚 \",\"👆 \"]},\"fistBump\":{\"interval\":80,\"frames\":[\"🤜    🤛 \",\"🤜    🤛 \",\"🤜    🤛 \",\" 🤜  🤛  \",\"  🤜🤛   \",\" 🤜✨🤛   \",\"🤜 ✨ 🤛  \"]},\"soccerHeader\":{\"interval\":80,\"frames\":[\" 🧑⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \",\"🧑 ⚽️ 🧑 \"]},\"mindblown\":{\"interval\":160,\"frames\":[\"😐 \",\"😐 \",\"😮 \",\"😮 \",\"😦 \",\"😦 \",\"😧 \",\"😧 \",\"🤯 \",\"💥 \",\"✨ \",\"  \",\"  \",\"  \"]},\"speaker\":{\"interval\":160,\"frames\":[\"🔈 \",\"🔉 \",\"🔊 \",\"🔉 \"]},\"orangePulse\":{\"interval\":100,\"frames\":[\"🔸 \",\"🔶 \",\"🟠 \",\"🟠 \",\"🔶 \"]},\"bluePulse\":{\"interval\":100,\"frames\":[\"🔹 \",\"🔷 \",\"🔵 \",\"🔵 \",\"🔷 \"]},\"orangeBluePulse\":{\"interval\":100,\"frames\":[\"🔸 \",\"🔶 \",\"🟠 \",\"🟠 \",\"🔶 \",\"🔹 \",\"🔷 \",\"🔵 \",\"🔵 \",\"🔷 \"]},\"timeTravel\":{\"interval\":100,\"frames\":[\"🕛 \",\"🕚 \",\"🕙 \",\"🕘 \",\"🕗 \",\"🕖 \",\"🕕 \",\"🕔 \",\"🕓 \",\"🕒 \",\"🕑 \",\"🕐 \"]},\"aesthetic\":{\"interval\":80,\"frames\":[\"▰▱▱▱▱▱▱\",\"▰▰▱▱▱▱▱\",\"▰▰▰▱▱▱▱\",\"▰▰▰▰▱▱▱\",\"▰▰▰▰▰▱▱\",\"▰▰▰▰▰▰▱\",\"▰▰▰▰▰▰▰\",\"▰▱▱▱▱▱▱\"]}}"); /***/ }), -/* 395 */ +/* 396 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(396); +const chalk = __webpack_require__(397); const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color'; @@ -48717,16 +48762,16 @@ module.exports = isSupported ? main : fallbacks; /***/ }), -/* 396 */ +/* 397 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const escapeStringRegexp = __webpack_require__(179); -const ansiStyles = __webpack_require__(397); -const stdoutColor = __webpack_require__(398).stdout; +const escapeStringRegexp = __webpack_require__(180); +const ansiStyles = __webpack_require__(398); +const stdoutColor = __webpack_require__(399).stdout; -const template = __webpack_require__(400); +const template = __webpack_require__(401); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -48952,12 +48997,12 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 397 */ +/* 398 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* WEBPACK VAR INJECTION */(function(module) { -const colorConvert = __webpack_require__(181); +const colorConvert = __webpack_require__(182); const wrapAnsi16 = (fn, offset) => function () { const code = fn.apply(colorConvert, arguments); @@ -49125,13 +49170,13 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(115)(module))) /***/ }), -/* 398 */ +/* 399 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const os = __webpack_require__(121); -const hasFlag = __webpack_require__(399); +const hasFlag = __webpack_require__(400); const env = process.env; @@ -49263,7 +49308,7 @@ module.exports = { /***/ }), -/* 399 */ +/* 400 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49278,7 +49323,7 @@ module.exports = (flag, argv) => { /***/ }), -/* 400 */ +/* 401 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49413,18 +49458,18 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 401 */ +/* 402 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(402); +const ansiRegex = __webpack_require__(403); module.exports = string => typeof string === 'string' ? string.replace(ansiRegex(), '') : string; /***/ }), -/* 402 */ +/* 403 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49441,14 +49486,14 @@ module.exports = ({onlyFirst = false} = {}) => { /***/ }), -/* 403 */ +/* 404 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var defaults = __webpack_require__(404) -var combining = __webpack_require__(406) +var defaults = __webpack_require__(405) +var combining = __webpack_require__(407) var DEFAULTS = { nul: 0, @@ -49547,10 +49592,10 @@ function bisearch(ucs) { /***/ }), -/* 404 */ +/* 405 */ /***/ (function(module, exports, __webpack_require__) { -var clone = __webpack_require__(405); +var clone = __webpack_require__(406); module.exports = function(options, defaults) { options = options || {}; @@ -49565,7 +49610,7 @@ module.exports = function(options, defaults) { }; /***/ }), -/* 405 */ +/* 406 */ /***/ (function(module, exports, __webpack_require__) { var clone = (function() { @@ -49737,7 +49782,7 @@ if ( true && module.exports) { /***/ }), -/* 406 */ +/* 407 */ /***/ (function(module, exports) { module.exports = [ @@ -49793,7 +49838,7 @@ module.exports = [ /***/ }), -/* 407 */ +/* 408 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49809,7 +49854,7 @@ module.exports = ({stream = process.stdout} = {}) => { /***/ }), -/* 408 */ +/* 409 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(138) @@ -49960,7 +50005,7 @@ MuteStream.prototype.close = proxy('close') /***/ }), -/* 409 */ +/* 410 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -49971,13 +50016,13 @@ Object.defineProperty(exports, "__esModule", { }); exports.RunCommand = void 0; -var _errors = __webpack_require__(163); +var _errors = __webpack_require__(164); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); -var _parallelize = __webpack_require__(145); +var _parallelize = __webpack_require__(146); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); /* * SPDX-License-Identifier: Apache-2.0 @@ -50040,7 +50085,7 @@ const RunCommand = { exports.RunCommand = RunCommand; /***/ }), -/* 410 */ +/* 411 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50051,15 +50096,15 @@ Object.defineProperty(exports, "__esModule", { }); exports.WatchCommand = void 0; -var _errors = __webpack_require__(163); +var _errors = __webpack_require__(164); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); -var _parallelize = __webpack_require__(145); +var _parallelize = __webpack_require__(146); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); -var _watch = __webpack_require__(411); +var _watch = __webpack_require__(412); /* * SPDX-License-Identifier: Apache-2.0 @@ -50155,7 +50200,7 @@ const WatchCommand = { exports.WatchCommand = WatchCommand; /***/ }), -/* 411 */ +/* 412 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -50168,7 +50213,7 @@ exports.waitUntilWatchIsReady = waitUntilWatchIsReady; var Rx = _interopRequireWildcard(__webpack_require__(8)); -var _operators = __webpack_require__(412); +var _operators = __webpack_require__(413); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } @@ -50249,141 +50294,141 @@ function waitUntilWatchIsReady(stream, opts = {}) { } /***/ }), -/* 412 */ +/* 413 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(413); +/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(414); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__["audit"]; }); -/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(414); +/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(415); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__["auditTime"]; }); -/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(415); +/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(416); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__["buffer"]; }); -/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(416); +/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(417); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__["bufferCount"]; }); -/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(417); +/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(418); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__["bufferTime"]; }); -/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(418); +/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(419); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__["bufferToggle"]; }); -/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(419); +/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(420); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__["bufferWhen"]; }); -/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(420); +/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(421); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__["catchError"]; }); -/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(421); +/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(422); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__["combineAll"]; }); -/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(422); +/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(423); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__["combineLatest"]; }); -/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(423); +/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(424); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__["concat"]; }); /* harmony import */ var _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(80); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatAll", function() { return _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__["concatAll"]; }); -/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(424); +/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(425); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__["concatMap"]; }); -/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(425); +/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(426); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__["concatMapTo"]; }); -/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(426); +/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(427); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "count", function() { return _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__["count"]; }); -/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(427); +/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(428); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__["debounce"]; }); -/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(428); +/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(429); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__["debounceTime"]; }); -/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(429); +/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(430); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__["defaultIfEmpty"]; }); -/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(430); +/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(431); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__["delay"]; }); -/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(432); +/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(433); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__["delayWhen"]; }); -/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(433); +/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(434); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__["dematerialize"]; }); -/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(434); +/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(435); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__["distinct"]; }); -/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(435); +/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(436); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__["distinctUntilChanged"]; }); -/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(436); +/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(437); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__["distinctUntilKeyChanged"]; }); -/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(437); +/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(438); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__["elementAt"]; }); -/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(440); +/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(441); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__["endWith"]; }); -/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(441); +/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(442); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "every", function() { return _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__["every"]; }); -/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(442); +/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(443); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__["exhaust"]; }); -/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(443); +/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(444); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__["exhaustMap"]; }); -/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(444); +/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(445); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__["expand"]; }); /* harmony import */ var _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(105); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__["filter"]; }); -/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(445); +/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(446); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__["finalize"]; }); -/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(446); +/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(447); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "find", function() { return _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__["find"]; }); -/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(447); +/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(448); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__["findIndex"]; }); -/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(448); +/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(449); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "first", function() { return _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__["first"]; }); /* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(31); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "groupBy", function() { return _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__["groupBy"]; }); -/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(449); +/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(450); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__["ignoreElements"]; }); -/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(450); +/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(451); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__["isEmpty"]; }); -/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(451); +/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(452); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "last", function() { return _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__["last"]; }); /* harmony import */ var _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(66); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "map", function() { return _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__["map"]; }); -/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(453); +/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(454); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__["mapTo"]; }); -/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(454); +/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(455); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__["materialize"]; }); -/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(455); +/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(456); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "max", function() { return _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__["max"]; }); -/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(458); +/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(459); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__["merge"]; }); /* harmony import */ var _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(81); @@ -50394,175 +50439,175 @@ __webpack_require__.r(__webpack_exports__); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "flatMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["flatMap"]; }); -/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(459); +/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(460); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__["mergeMapTo"]; }); -/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(460); +/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(461); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__["mergeScan"]; }); -/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(461); +/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(462); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "min", function() { return _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__["min"]; }); -/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(462); +/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(463); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__["multicast"]; }); /* harmony import */ var _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(41); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "observeOn", function() { return _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__["observeOn"]; }); -/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(463); +/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(464); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__["onErrorResumeNext"]; }); -/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(464); +/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(465); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__["pairwise"]; }); -/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(465); +/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(466); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__["partition"]; }); -/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(466); +/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(467); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__["pluck"]; }); -/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(467); +/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(468); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__["publish"]; }); -/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(468); +/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(469); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__["publishBehavior"]; }); -/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(469); +/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(470); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__["publishLast"]; }); -/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(470); +/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(471); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__["publishReplay"]; }); -/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(471); +/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(472); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "race", function() { return _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__["race"]; }); -/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(456); +/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(457); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__["reduce"]; }); -/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(472); +/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(473); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__["repeat"]; }); -/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(473); +/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(474); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__["repeatWhen"]; }); -/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(474); +/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(475); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__["retry"]; }); -/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(475); +/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(476); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__["retryWhen"]; }); /* harmony import */ var _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(30); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refCount", function() { return _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__["refCount"]; }); -/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(476); +/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(477); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__["sample"]; }); -/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(477); +/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(478); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__["sampleTime"]; }); -/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(457); +/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(458); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__["scan"]; }); -/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(478); +/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(479); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__["sequenceEqual"]; }); -/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(479); +/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(480); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "share", function() { return _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__["share"]; }); -/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(480); +/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(481); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__["shareReplay"]; }); -/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(481); +/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(482); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "single", function() { return _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__["single"]; }); -/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(482); +/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(483); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__["skip"]; }); -/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(483); +/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(484); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__["skipLast"]; }); -/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(484); +/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(485); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__["skipUntil"]; }); -/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(485); +/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(486); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__["skipWhile"]; }); -/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(486); +/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(487); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__["startWith"]; }); -/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(487); +/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(488); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__["subscribeOn"]; }); -/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(489); +/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(490); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__["switchAll"]; }); -/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(490); +/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(491); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__["switchMap"]; }); -/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(491); +/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(492); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__["switchMapTo"]; }); -/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(439); +/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(440); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "take", function() { return _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__["take"]; }); -/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(452); +/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(453); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__["takeLast"]; }); -/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(492); +/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(493); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__["takeUntil"]; }); -/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(493); +/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(494); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__["takeWhile"]; }); -/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(494); +/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(495); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__["tap"]; }); -/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(495); +/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(496); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__["throttle"]; }); -/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(496); +/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(497); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__["throttleTime"]; }); -/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(438); +/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(439); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__["throwIfEmpty"]; }); -/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(497); +/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(498); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__["timeInterval"]; }); -/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(498); +/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(499); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__["timeout"]; }); -/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(499); +/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(500); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__["timeoutWith"]; }); -/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(500); +/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(501); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__["timestamp"]; }); -/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(501); +/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(502); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__["toArray"]; }); -/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(502); +/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(503); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "window", function() { return _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__["window"]; }); -/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(503); +/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(504); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__["windowCount"]; }); -/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(504); +/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(505); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__["windowTime"]; }); -/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(505); +/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(506); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__["windowToggle"]; }); -/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(506); +/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(507); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__["windowWhen"]; }); -/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(507); +/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(508); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__["withLatestFrom"]; }); -/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(508); +/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(509); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__["zip"]; }); -/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(509); +/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(510); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__["zipAll"]; }); /** PURE_IMPORTS_START PURE_IMPORTS_END */ @@ -50673,7 +50718,7 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 413 */ +/* 414 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50752,14 +50797,14 @@ var AuditSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 414 */ +/* 415 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return auditTime; }); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(413); +/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(414); /* harmony import */ var _observable_timer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(108); /** PURE_IMPORTS_START _scheduler_async,_audit,_observable_timer PURE_IMPORTS_END */ @@ -50775,7 +50820,7 @@ function auditTime(duration, scheduler) { /***/ }), -/* 415 */ +/* 416 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50822,7 +50867,7 @@ var BufferSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 416 */ +/* 417 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -50923,7 +50968,7 @@ var BufferSkipCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 417 */ +/* 418 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51084,7 +51129,7 @@ function dispatchBufferClose(arg) { /***/ }), -/* 418 */ +/* 419 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51203,7 +51248,7 @@ var BufferToggleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 419 */ +/* 420 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51296,7 +51341,7 @@ var BufferWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 420 */ +/* 421 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51356,7 +51401,7 @@ var CatchSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 421 */ +/* 422 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51372,7 +51417,7 @@ function combineAll(project) { /***/ }), -/* 422 */ +/* 423 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51404,7 +51449,7 @@ function combineLatest() { /***/ }), -/* 423 */ +/* 424 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51424,7 +51469,7 @@ function concat() { /***/ }), -/* 424 */ +/* 425 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51440,13 +51485,13 @@ function concatMap(project, resultSelector) { /***/ }), -/* 425 */ +/* 426 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return concatMapTo; }); -/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(424); +/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(425); /** PURE_IMPORTS_START _concatMap PURE_IMPORTS_END */ function concatMapTo(innerObservable, resultSelector) { @@ -51456,7 +51501,7 @@ function concatMapTo(innerObservable, resultSelector) { /***/ }), -/* 426 */ +/* 427 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51521,7 +51566,7 @@ var CountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 427 */ +/* 428 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51606,7 +51651,7 @@ var DebounceSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 428 */ +/* 429 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51682,7 +51727,7 @@ function dispatchNext(subscriber) { /***/ }), -/* 429 */ +/* 430 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51732,7 +51777,7 @@ var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 430 */ +/* 431 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51740,7 +51785,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return delay; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(431); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(432); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); /* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(42); /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_Subscriber,_Notification PURE_IMPORTS_END */ @@ -51839,7 +51884,7 @@ var DelayMessage = /*@__PURE__*/ (function () { /***/ }), -/* 431 */ +/* 432 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51853,7 +51898,7 @@ function isDate(value) { /***/ }), -/* 432 */ +/* 433 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -51999,7 +52044,7 @@ var SubscriptionDelaySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 433 */ +/* 434 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52037,7 +52082,7 @@ var DeMaterializeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 434 */ +/* 435 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52113,7 +52158,7 @@ var DistinctSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 435 */ +/* 436 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52184,13 +52229,13 @@ var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 436 */ +/* 437 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return distinctUntilKeyChanged; }); -/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(435); +/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(436); /** PURE_IMPORTS_START _distinctUntilChanged PURE_IMPORTS_END */ function distinctUntilKeyChanged(key, compare) { @@ -52200,7 +52245,7 @@ function distinctUntilKeyChanged(key, compare) { /***/ }), -/* 437 */ +/* 438 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52208,9 +52253,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return elementAt; }); /* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(62); /* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(105); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(438); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(429); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(439); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(439); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(430); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(440); /** PURE_IMPORTS_START _util_ArgumentOutOfRangeError,_filter,_throwIfEmpty,_defaultIfEmpty,_take PURE_IMPORTS_END */ @@ -52232,7 +52277,7 @@ function elementAt(index, defaultValue) { /***/ }), -/* 438 */ +/* 439 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52298,7 +52343,7 @@ function defaultErrorFactory() { /***/ }), -/* 439 */ +/* 440 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52360,7 +52405,7 @@ var TakeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 440 */ +/* 441 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52382,7 +52427,7 @@ function endWith() { /***/ }), -/* 441 */ +/* 442 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52444,7 +52489,7 @@ var EverySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 442 */ +/* 443 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52498,7 +52543,7 @@ var SwitchFirstSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 443 */ +/* 444 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52592,7 +52637,7 @@ var ExhaustMapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 444 */ +/* 445 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52704,7 +52749,7 @@ var ExpandSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 445 */ +/* 446 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52742,7 +52787,7 @@ var FinallySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 446 */ +/* 447 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52814,13 +52859,13 @@ var FindValueSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 447 */ +/* 448 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return findIndex; }); -/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(446); +/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(447); /** PURE_IMPORTS_START _operators_find PURE_IMPORTS_END */ function findIndex(predicate, thisArg) { @@ -52830,7 +52875,7 @@ function findIndex(predicate, thisArg) { /***/ }), -/* 448 */ +/* 449 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52838,9 +52883,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "first", function() { return first; }); /* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); /* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(105); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(439); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(429); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(438); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(440); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(430); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(439); /* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); /** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */ @@ -52857,7 +52902,7 @@ function first(predicate, defaultValue) { /***/ }), -/* 449 */ +/* 450 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52894,7 +52939,7 @@ var IgnoreElementsSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 450 */ +/* 451 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52938,7 +52983,7 @@ var IsEmptySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 451 */ +/* 452 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -52946,9 +52991,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "last", function() { return last; }); /* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); /* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(105); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(452); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(438); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(429); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(453); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(439); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(430); /* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); /** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */ @@ -52965,7 +53010,7 @@ function last(predicate, defaultValue) { /***/ }), -/* 452 */ +/* 453 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53042,7 +53087,7 @@ var TakeLastSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 453 */ +/* 454 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53081,7 +53126,7 @@ var MapToSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 454 */ +/* 455 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53131,13 +53176,13 @@ var MaterializeSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 455 */ +/* 456 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(456); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(457); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function max(comparer) { @@ -53150,15 +53195,15 @@ function max(comparer) { /***/ }), -/* 456 */ +/* 457 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return reduce; }); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(457); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(452); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(429); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(458); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(453); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(430); /* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(24); /** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */ @@ -53179,7 +53224,7 @@ function reduce(accumulator, seed) { /***/ }), -/* 457 */ +/* 458 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53261,7 +53306,7 @@ var ScanSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 458 */ +/* 459 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53281,7 +53326,7 @@ function merge() { /***/ }), -/* 459 */ +/* 460 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53306,7 +53351,7 @@ function mergeMapTo(innerObservable, resultSelector, concurrent) { /***/ }), -/* 460 */ +/* 461 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53415,13 +53460,13 @@ var MergeScanSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 461 */ +/* 462 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(456); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(457); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function min(comparer) { @@ -53434,7 +53479,7 @@ function min(comparer) { /***/ }), -/* 462 */ +/* 463 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53483,7 +53528,7 @@ var MulticastOperator = /*@__PURE__*/ (function () { /***/ }), -/* 463 */ +/* 464 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53573,7 +53618,7 @@ var OnErrorResumeNextSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 464 */ +/* 465 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53621,7 +53666,7 @@ var PairwiseSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 465 */ +/* 466 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53644,7 +53689,7 @@ function partition(predicate, thisArg) { /***/ }), -/* 466 */ +/* 467 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53684,14 +53729,14 @@ function plucker(props, length) { /***/ }), -/* 467 */ +/* 468 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return publish; }); /* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(27); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(462); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(463); /** PURE_IMPORTS_START _Subject,_multicast PURE_IMPORTS_END */ @@ -53704,14 +53749,14 @@ function publish(selector) { /***/ }), -/* 468 */ +/* 469 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return publishBehavior; }); /* harmony import */ var _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(32); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(462); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(463); /** PURE_IMPORTS_START _BehaviorSubject,_multicast PURE_IMPORTS_END */ @@ -53722,14 +53767,14 @@ function publishBehavior(value) { /***/ }), -/* 469 */ +/* 470 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return publishLast; }); /* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(50); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(462); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(463); /** PURE_IMPORTS_START _AsyncSubject,_multicast PURE_IMPORTS_END */ @@ -53740,14 +53785,14 @@ function publishLast() { /***/ }), -/* 470 */ +/* 471 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return publishReplay; }); /* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(33); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(462); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(463); /** PURE_IMPORTS_START _ReplaySubject,_multicast PURE_IMPORTS_END */ @@ -53763,7 +53808,7 @@ function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) { /***/ }), -/* 471 */ +/* 472 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53790,7 +53835,7 @@ function race() { /***/ }), -/* 472 */ +/* 473 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53855,7 +53900,7 @@ var RepeatSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 473 */ +/* 474 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -53949,7 +53994,7 @@ var RepeatWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 474 */ +/* 475 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54002,7 +54047,7 @@ var RetrySubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 475 */ +/* 476 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54088,7 +54133,7 @@ var RetryWhenSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 476 */ +/* 477 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54143,7 +54188,7 @@ var SampleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 477 */ +/* 478 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54203,7 +54248,7 @@ function dispatchNotification(state) { /***/ }), -/* 478 */ +/* 479 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54326,13 +54371,13 @@ var SequenceEqualCompareToSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 479 */ +/* 480 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "share", function() { return share; }); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(462); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(463); /* harmony import */ var _refCount__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(30); /* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(27); /** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */ @@ -54349,7 +54394,7 @@ function share() { /***/ }), -/* 480 */ +/* 481 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54424,7 +54469,7 @@ function shareReplayOperator(_a) { /***/ }), -/* 481 */ +/* 482 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54504,7 +54549,7 @@ var SingleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 482 */ +/* 483 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54546,7 +54591,7 @@ var SkipSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 483 */ +/* 484 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54608,7 +54653,7 @@ var SkipLastSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 484 */ +/* 485 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54665,7 +54710,7 @@ var SkipUntilSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 485 */ +/* 486 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54721,7 +54766,7 @@ var SkipWhileSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 486 */ +/* 487 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54750,13 +54795,13 @@ function startWith() { /***/ }), -/* 487 */ +/* 488 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return subscribeOn; }); -/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(488); +/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(489); /** PURE_IMPORTS_START _observable_SubscribeOnObservable PURE_IMPORTS_END */ function subscribeOn(scheduler, delay) { @@ -54781,7 +54826,7 @@ var SubscribeOnOperator = /*@__PURE__*/ (function () { /***/ }), -/* 488 */ +/* 489 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54845,13 +54890,13 @@ var SubscribeOnObservable = /*@__PURE__*/ (function (_super) { /***/ }), -/* 489 */ +/* 490 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return switchAll; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(490); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(491); /* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(25); /** PURE_IMPORTS_START _switchMap,_util_identity PURE_IMPORTS_END */ @@ -54863,7 +54908,7 @@ function switchAll() { /***/ }), -/* 490 */ +/* 491 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54951,13 +54996,13 @@ var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 491 */ +/* 492 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return switchMapTo; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(490); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(491); /** PURE_IMPORTS_START _switchMap PURE_IMPORTS_END */ function switchMapTo(innerObservable, resultSelector) { @@ -54967,7 +55012,7 @@ function switchMapTo(innerObservable, resultSelector) { /***/ }), -/* 492 */ +/* 493 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55015,7 +55060,7 @@ var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 493 */ +/* 494 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55083,7 +55128,7 @@ var TakeWhileSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 494 */ +/* 495 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55171,7 +55216,7 @@ var TapSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 495 */ +/* 496 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55273,7 +55318,7 @@ var ThrottleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 496 */ +/* 497 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55282,7 +55327,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); -/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(495); +/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(496); /** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async,_throttle PURE_IMPORTS_END */ @@ -55371,7 +55416,7 @@ function dispatchNext(arg) { /***/ }), -/* 497 */ +/* 498 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55379,7 +55424,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return timeInterval; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TimeInterval", function() { return TimeInterval; }); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(457); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(458); /* harmony import */ var _observable_defer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91); /* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(66); /** PURE_IMPORTS_START _scheduler_async,_scan,_observable_defer,_map PURE_IMPORTS_END */ @@ -55415,7 +55460,7 @@ var TimeInterval = /*@__PURE__*/ (function () { /***/ }), -/* 498 */ +/* 499 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55423,7 +55468,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return timeout; }); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); /* harmony import */ var _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(64); -/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(499); +/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); /* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(49); /** PURE_IMPORTS_START _scheduler_async,_util_TimeoutError,_timeoutWith,_observable_throwError PURE_IMPORTS_END */ @@ -55440,7 +55485,7 @@ function timeout(due, scheduler) { /***/ }), -/* 499 */ +/* 500 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55448,7 +55493,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return timeoutWith; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(431); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(432); /* harmony import */ var _innerSubscribe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(90); /** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_innerSubscribe PURE_IMPORTS_END */ @@ -55519,7 +55564,7 @@ var TimeoutWithSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 500 */ +/* 501 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55549,13 +55594,13 @@ var Timestamp = /*@__PURE__*/ (function () { /***/ }), -/* 501 */ +/* 502 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return toArray; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(456); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(457); /** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ function toArrayReducer(arr, item, index) { @@ -55572,7 +55617,7 @@ function toArray() { /***/ }), -/* 502 */ +/* 503 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55650,7 +55695,7 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 503 */ +/* 504 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55740,7 +55785,7 @@ var WindowCountSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 504 */ +/* 505 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55910,7 +55955,7 @@ function dispatchWindowClose(state) { /***/ }), -/* 505 */ +/* 506 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56053,7 +56098,7 @@ var WindowToggleSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 506 */ +/* 507 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56150,7 +56195,7 @@ var WindowSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 507 */ +/* 508 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56245,7 +56290,7 @@ var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) { /***/ }), -/* 508 */ +/* 509 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56267,7 +56312,7 @@ function zip() { /***/ }), -/* 509 */ +/* 510 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56283,7 +56328,7 @@ function zipAll(project) { /***/ }), -/* 510 */ +/* 511 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56294,15 +56339,15 @@ Object.defineProperty(exports, "__esModule", { }); exports.runCommand = runCommand; -var _errors = __webpack_require__(163); +var _errors = __webpack_require__(164); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); -var _projects_tree = __webpack_require__(289); +var _projects_tree = __webpack_require__(296); -var _opensearch_dashboards = __webpack_require__(511); +var _opensearch_dashboards = __webpack_require__(512); /* * SPDX-License-Identifier: Apache-2.0 @@ -56394,7 +56439,7 @@ function toArray(value) { } /***/ }), -/* 511 */ +/* 512 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56407,15 +56452,15 @@ exports.OpenSearchDashboards = void 0; var _path = _interopRequireDefault(__webpack_require__(4)); -var _multimatch = _interopRequireDefault(__webpack_require__(512)); +var _multimatch = _interopRequireDefault(__webpack_require__(513)); -var _isPathInside = _interopRequireDefault(__webpack_require__(380)); +var _isPathInside = _interopRequireDefault(__webpack_require__(381)); -var _yarn_lock = __webpack_require__(285); +var _yarn_lock = __webpack_require__(286); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); -var _config = __webpack_require__(282); +var _config = __webpack_require__(283); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -56545,15 +56590,15 @@ class OpenSearchDashboards { exports.OpenSearchDashboards = OpenSearchDashboards; /***/ }), -/* 512 */ +/* 513 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const minimatch = __webpack_require__(150); -const arrayUnion = __webpack_require__(299); -const arrayDiffer = __webpack_require__(513); -const arrify = __webpack_require__(514); +const minimatch = __webpack_require__(151); +const arrayUnion = __webpack_require__(300); +const arrayDiffer = __webpack_require__(514); +const arrify = __webpack_require__(515); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -56577,7 +56622,7 @@ module.exports = (list, patterns, options = {}) => { /***/ }), -/* 513 */ +/* 514 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56592,7 +56637,7 @@ module.exports = arrayDiffer; /***/ }), -/* 514 */ +/* 515 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56622,7 +56667,7 @@ module.exports = arrify; /***/ }), -/* 515 */ +/* 516 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56638,10 +56683,10 @@ Object.defineProperty(exports, "buildProductionProjects", { } }); -var _build_production_projects = __webpack_require__(516); +var _build_production_projects = __webpack_require__(517); /***/ }), -/* 516 */ +/* 517 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56652,21 +56697,21 @@ Object.defineProperty(exports, "__esModule", { }); exports.buildProductionProjects = buildProductionProjects; -var _cpy = _interopRequireDefault(__webpack_require__(517)); +var _cpy = _interopRequireDefault(__webpack_require__(518)); -var _del = _interopRequireDefault(__webpack_require__(297)); +var _del = _interopRequireDefault(__webpack_require__(298)); var _path = __webpack_require__(4); -var _config = __webpack_require__(282); +var _config = __webpack_require__(283); var _fs = __webpack_require__(131); -var _log = __webpack_require__(144); +var _log = __webpack_require__(145); -var _package_json = __webpack_require__(165); +var _package_json = __webpack_require__(166); -var _projects = __webpack_require__(146); +var _projects = __webpack_require__(147); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -56796,22 +56841,22 @@ async function copyToBuild(project, opensearchDashboardsRoot, buildRoot) { } /***/ }), -/* 517 */ +/* 518 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const EventEmitter = __webpack_require__(156); +const EventEmitter = __webpack_require__(157); const path = __webpack_require__(4); const os = __webpack_require__(121); -const pMap = __webpack_require__(518); -const arrify = __webpack_require__(514); -const globby = __webpack_require__(519); -const hasGlob = __webpack_require__(702); -const cpFile = __webpack_require__(704); -const junk = __webpack_require__(714); -const pFilter = __webpack_require__(715); -const CpyError = __webpack_require__(717); +const pMap = __webpack_require__(519); +const arrify = __webpack_require__(515); +const globby = __webpack_require__(520); +const hasGlob = __webpack_require__(700); +const cpFile = __webpack_require__(702); +const junk = __webpack_require__(712); +const pFilter = __webpack_require__(713); +const CpyError = __webpack_require__(715); const defaultOptions = { ignoreJunk: true @@ -56962,12 +57007,12 @@ module.exports = (source, destination, { /***/ }), -/* 518 */ +/* 519 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(383); +const AggregateError = __webpack_require__(384); module.exports = async ( iterable, @@ -57050,17 +57095,17 @@ module.exports = async ( /***/ }), -/* 519 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const arrayUnion = __webpack_require__(520); -const glob = __webpack_require__(147); -const fastGlob = __webpack_require__(522); -const dirGlob = __webpack_require__(696); -const gitignore = __webpack_require__(699); +const arrayUnion = __webpack_require__(521); +const glob = __webpack_require__(148); +const fastGlob = __webpack_require__(523); +const dirGlob = __webpack_require__(694); +const gitignore = __webpack_require__(697); const DEFAULT_FILTER = () => false; @@ -57205,12 +57250,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 520 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(521); +var arrayUniq = __webpack_require__(522); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -57218,7 +57263,7 @@ module.exports = function () { /***/ }), -/* 521 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57287,10 +57332,10 @@ if ('Set' in global) { /***/ }), -/* 522 */ +/* 523 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(523); +const pkg = __webpack_require__(524); module.exports = pkg.async; module.exports.default = pkg.async; @@ -57303,375 +57348,375 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 523 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(524); -var taskManager = __webpack_require__(525); -var reader_async_1 = __webpack_require__(667); -var reader_stream_1 = __webpack_require__(691); -var reader_sync_1 = __webpack_require__(692); -var arrayUtils = __webpack_require__(694); -var streamUtils = __webpack_require__(695); -/** - * 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'; -} + +Object.defineProperty(exports, "__esModule", { value: true }); +var optionsManager = __webpack_require__(525); +var taskManager = __webpack_require__(526); +var reader_async_1 = __webpack_require__(665); +var reader_stream_1 = __webpack_require__(689); +var reader_sync_1 = __webpack_require__(690); +var arrayUtils = __webpack_require__(692); +var streamUtils = __webpack_require__(693); +/** + * 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'; +} /***/ }), -/* 524 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { "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; + +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; /***/ }), -/* 525 */ +/* 526 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(526); -/** - * 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; + +Object.defineProperty(exports, "__esModule", { value: true }); +var patternUtils = __webpack_require__(527); +/** + * 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; /***/ }), -/* 526 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(4); -var globParent = __webpack_require__(309); -var isGlob = __webpack_require__(310); -var micromatch = __webpack_require__(527); -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; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(4); +var globParent = __webpack_require__(310); +var isGlob = __webpack_require__(311); +var micromatch = __webpack_require__(528); +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; /***/ }), -/* 527 */ +/* 528 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -57682,18 +57727,18 @@ exports.matchAny = matchAny; */ var util = __webpack_require__(112); -var braces = __webpack_require__(528); -var toRegex = __webpack_require__(529); -var extend = __webpack_require__(632); +var braces = __webpack_require__(529); +var toRegex = __webpack_require__(530); +var extend = __webpack_require__(543); /** * Local dependencies */ -var compilers = __webpack_require__(634); -var parsers = __webpack_require__(663); -var cache = __webpack_require__(664); -var utils = __webpack_require__(665); +var compilers = __webpack_require__(632); +var parsers = __webpack_require__(661); +var cache = __webpack_require__(662); +var utils = __webpack_require__(663); var MAX_LENGTH = 1024 * 64; /** @@ -58555,7 +58600,7 @@ module.exports = micromatch; /***/ }), -/* 528 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -58565,18 +58610,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(529); -var unique = __webpack_require__(549); -var extend = __webpack_require__(550); +var toRegex = __webpack_require__(530); +var unique = __webpack_require__(548); +var extend = __webpack_require__(549); /** * Local dependencies */ -var compilers = __webpack_require__(552); -var parsers = __webpack_require__(563); -var Braces = __webpack_require__(567); -var utils = __webpack_require__(553); +var compilers = __webpack_require__(551); +var parsers = __webpack_require__(561); +var Braces = __webpack_require__(565); +var utils = __webpack_require__(552); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -58880,16 +58925,16 @@ module.exports = braces; /***/ }), -/* 529 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(530); -var define = __webpack_require__(536); -var extend = __webpack_require__(542); -var not = __webpack_require__(546); +var safe = __webpack_require__(531); +var define = __webpack_require__(537); +var extend = __webpack_require__(543); +var not = __webpack_require__(547); var MAX_LENGTH = 1024 * 64; /** @@ -59042,10 +59087,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 530 */ +/* 531 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(531); +var parse = __webpack_require__(532); var types = parse.types; module.exports = function (re, opts) { @@ -59091,13 +59136,13 @@ function isRegExp (x) { /***/ }), -/* 531 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(532); -var types = __webpack_require__(533); -var sets = __webpack_require__(534); -var positions = __webpack_require__(535); +var util = __webpack_require__(533); +var types = __webpack_require__(534); +var sets = __webpack_require__(535); +var positions = __webpack_require__(536); module.exports = function(regexpStr) { @@ -59379,11 +59424,11 @@ module.exports.types = types; /***/ }), -/* 532 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(533); -var sets = __webpack_require__(534); +var types = __webpack_require__(534); +var sets = __webpack_require__(535); // All of these are private and only used by randexp. @@ -59496,7 +59541,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 533 */ +/* 534 */ /***/ (function(module, exports) { module.exports = { @@ -59512,10 +59557,10 @@ module.exports = { /***/ }), -/* 534 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(533); +var types = __webpack_require__(534); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -59600,10 +59645,10 @@ exports.anyChar = function() { /***/ }), -/* 535 */ +/* 536 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(533); +var types = __webpack_require__(534); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -59623,7 +59668,7 @@ exports.end = function() { /***/ }), -/* 536 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59636,8 +59681,8 @@ exports.end = function() { -var isobject = __webpack_require__(537); -var isDescriptor = __webpack_require__(538); +var isobject = __webpack_require__(538); +var isDescriptor = __webpack_require__(539); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -59668,7 +59713,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 537 */ +/* 538 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59687,7 +59732,7 @@ module.exports = function isObject(val) { /***/ }), -/* 538 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59700,9 +59745,9 @@ module.exports = function isObject(val) { -var typeOf = __webpack_require__(539); -var isAccessor = __webpack_require__(540); -var isData = __webpack_require__(541); +var typeOf = __webpack_require__(540); +var isAccessor = __webpack_require__(541); +var isData = __webpack_require__(542); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -59716,7 +59761,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 539 */ +/* 540 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -59851,7 +59896,7 @@ function isBuffer(val) { /***/ }), -/* 540 */ +/* 541 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59864,7 +59909,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(540); // accessor descriptor properties var accessor = { @@ -59927,7 +59972,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 541 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59940,7 +59985,7 @@ module.exports = isAccessorDescriptor; -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(540); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -59983,14 +60028,14 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 542 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(543); -var assignSymbols = __webpack_require__(545); +var isExtendable = __webpack_require__(544); +var assignSymbols = __webpack_require__(546); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -60050,7 +60095,7 @@ function isEnum(obj, key) { /***/ }), -/* 543 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60063,7 +60108,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(545); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -60071,7 +60116,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 544 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60084,7 +60129,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(537); +var isObject = __webpack_require__(538); function isObjectObject(o) { return isObject(o) === true @@ -60115,7 +60160,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 545 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60162,14 +60207,14 @@ module.exports = function(receiver, objects) { /***/ }), -/* 546 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(547); -var safe = __webpack_require__(530); +var extend = __webpack_require__(543); +var safe = __webpack_require__(531); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -60240,98 +60285,10 @@ toRegex.create = function(pattern, options) { module.exports = toRegex; -/***/ }), -/* 547 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(548); -var assignSymbols = __webpack_require__(545); - -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); -} - - /***/ }), /* 548 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(544); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 549 */ -/***/ (function(module, exports, __webpack_require__) { - "use strict"; /*! * array-unique @@ -60379,13 +60336,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 550 */ +/* 549 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(551); +var isObject = __webpack_require__(550); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -60419,7 +60376,7 @@ function hasOwn(obj, key) { /***/ }), -/* 551 */ +/* 550 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60439,13 +60396,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 552 */ +/* 551 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(553); +var utils = __webpack_require__(552); module.exports = function(braces, options) { braces.compiler @@ -60728,25 +60685,25 @@ function hasQueue(node) { /***/ }), -/* 553 */ +/* 552 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(554); +var splitString = __webpack_require__(553); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(550); -utils.flatten = __webpack_require__(557); -utils.isObject = __webpack_require__(537); -utils.fillRange = __webpack_require__(558); -utils.repeat = __webpack_require__(562); -utils.unique = __webpack_require__(549); +utils.extend = __webpack_require__(549); +utils.flatten = __webpack_require__(554); +utils.isObject = __webpack_require__(538); +utils.fillRange = __webpack_require__(555); +utils.repeat = __webpack_require__(560); +utils.unique = __webpack_require__(548); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -61078,7 +61035,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 554 */ +/* 553 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61091,7 +61048,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(555); +var extend = __webpack_require__(543); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -61256,95 +61213,7 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 555 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(556); -var assignSymbols = __webpack_require__(545); - -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); -} - - -/***/ }), -/* 556 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(544); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 557 */ +/* 554 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61373,7 +61242,7 @@ function flat(arr, res) { /***/ }), -/* 558 */ +/* 555 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61387,10 +61256,10 @@ function flat(arr, res) { var util = __webpack_require__(112); -var isNumber = __webpack_require__(559); -var extend = __webpack_require__(550); -var repeat = __webpack_require__(560); -var toRegex = __webpack_require__(561); +var isNumber = __webpack_require__(556); +var extend = __webpack_require__(557); +var repeat = __webpack_require__(558); +var toRegex = __webpack_require__(559); /** * Return a range of numbers or letters. @@ -61588,7 +61457,7 @@ module.exports = fillRange; /***/ }), -/* 559 */ +/* 556 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61601,7 +61470,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(540); module.exports = function isNumber(num) { var type = typeOf(num); @@ -61617,7 +61486,47 @@ module.exports = function isNumber(num) { /***/ }), -/* 560 */ +/* 557 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isObject = __webpack_require__(550); + +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); +} + + +/***/ }), +/* 558 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61694,7 +61603,7 @@ function repeat(str, num) { /***/ }), -/* 561 */ +/* 559 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61707,8 +61616,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(560); -var isNumber = __webpack_require__(559); +var repeat = __webpack_require__(558); +var isNumber = __webpack_require__(556); var cache = {}; function toRegexRange(min, max, options) { @@ -61995,7 +61904,7 @@ module.exports = toRegexRange; /***/ }), -/* 562 */ +/* 560 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62024,14 +61933,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 563 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(564); -var utils = __webpack_require__(553); +var Node = __webpack_require__(562); +var utils = __webpack_require__(552); /** * Braces parsers @@ -62391,15 +62300,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 564 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(537); -var define = __webpack_require__(565); -var utils = __webpack_require__(566); +var isObject = __webpack_require__(538); +var define = __webpack_require__(563); +var utils = __webpack_require__(564); var ownNames; /** @@ -62890,7 +62799,7 @@ exports = module.exports = Node; /***/ }), -/* 565 */ +/* 563 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62903,7 +62812,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(538); +var isDescriptor = __webpack_require__(539); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -62928,13 +62837,13 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 566 */ +/* 564 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(540); var utils = module.exports; /** @@ -63954,17 +63863,17 @@ function assert(val, message) { /***/ }), -/* 567 */ +/* 565 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(550); -var Snapdragon = __webpack_require__(568); -var compilers = __webpack_require__(552); -var parsers = __webpack_require__(563); -var utils = __webpack_require__(553); +var extend = __webpack_require__(549); +var Snapdragon = __webpack_require__(566); +var compilers = __webpack_require__(551); +var parsers = __webpack_require__(561); +var utils = __webpack_require__(552); /** * Customize Snapdragon parser and renderer @@ -64065,17 +63974,17 @@ module.exports = Braces; /***/ }), -/* 568 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(569); -var define = __webpack_require__(594); -var Compiler = __webpack_require__(601); +var Base = __webpack_require__(567); +var define = __webpack_require__(593); +var Compiler = __webpack_require__(600); var Parser = __webpack_require__(629); -var utils = __webpack_require__(609); +var utils = __webpack_require__(608); var regexCache = {}; var cache = {}; @@ -64246,20 +64155,20 @@ module.exports.Parser = Parser; /***/ }), -/* 569 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var define = __webpack_require__(570); -var CacheBase = __webpack_require__(571); -var Emitter = __webpack_require__(572); -var isObject = __webpack_require__(537); -var merge = __webpack_require__(589); -var pascal = __webpack_require__(592); -var cu = __webpack_require__(593); +var define = __webpack_require__(568); +var CacheBase = __webpack_require__(569); +var Emitter = __webpack_require__(570); +var isObject = __webpack_require__(538); +var merge = __webpack_require__(588); +var pascal = __webpack_require__(591); +var cu = __webpack_require__(592); /** * Optionally define a custom `cache` namespace to use. @@ -64688,7 +64597,7 @@ module.exports.namespace = namespace; /***/ }), -/* 570 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64701,7 +64610,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(538); +var isDescriptor = __webpack_require__(539); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -64726,21 +64635,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 571 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(537); -var Emitter = __webpack_require__(572); -var visit = __webpack_require__(573); -var toPath = __webpack_require__(576); -var union = __webpack_require__(577); -var del = __webpack_require__(581); -var get = __webpack_require__(579); -var has = __webpack_require__(587); -var set = __webpack_require__(580); +var isObject = __webpack_require__(538); +var Emitter = __webpack_require__(570); +var visit = __webpack_require__(571); +var toPath = __webpack_require__(574); +var union = __webpack_require__(575); +var del = __webpack_require__(580); +var get = __webpack_require__(577); +var has = __webpack_require__(586); +var set = __webpack_require__(578); /** * Create a `Cache` constructor that when instantiated will @@ -64994,188 +64903,188 @@ module.exports.namespace = namespace; /***/ }), -/* 572 */ +/* 570 */ /***/ (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; -}; + +/** + * 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; +}; /***/ }), -/* 573 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65188,8 +65097,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(574); -var mapVisit = __webpack_require__(575); +var visit = __webpack_require__(572); +var mapVisit = __webpack_require__(573); module.exports = function(collection, method, val) { var result; @@ -65212,7 +65121,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 574 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65225,7 +65134,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(537); +var isObject = __webpack_require__(538); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -65252,14 +65161,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 575 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var visit = __webpack_require__(574); +var visit = __webpack_require__(572); /** * Map `visit` over an array of objects. @@ -65296,7 +65205,7 @@ function isObject(val) { /***/ }), -/* 576 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65309,7 +65218,7 @@ function isObject(val) { -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(540); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -65336,16 +65245,16 @@ function filter(arr) { /***/ }), -/* 577 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(551); -var union = __webpack_require__(578); -var get = __webpack_require__(579); -var set = __webpack_require__(580); +var isObject = __webpack_require__(550); +var union = __webpack_require__(576); +var get = __webpack_require__(577); +var set = __webpack_require__(578); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -65373,7 +65282,7 @@ function arrayify(val) { /***/ }), -/* 578 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65409,7 +65318,7 @@ module.exports = function union(init) { /***/ }), -/* 579 */ +/* 577 */ /***/ (function(module, exports) { /*! @@ -65465,69 +65374,205 @@ function toString(val) { /***/ }), -/* 580 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! * set-value * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Copyright (c) Jon Schlinkert (https://github.com/jonschlinkert). * Released under the MIT License. */ -var split = __webpack_require__(554); -var extend = __webpack_require__(550); -var isPlainObject = __webpack_require__(544); -var isObject = __webpack_require__(551); +const { deleteProperty } = Reflect; +const isPrimitive = __webpack_require__(579); +const isPlainObject = __webpack_require__(545); -module.exports = function(obj, prop, val) { - if (!isObject(obj)) { - return obj; +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 (Array.isArray(prop)) { - prop = [].concat.apply([], prop).join('.'); + if (isUnsafeKey(key)) { + throw new Error(`Cannot set unsafe key: "${key}"`); } +}; - if (typeof prop !== 'string') { - return obj; +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]; } - var keys = split(prop, {sep: '.', brackets: true}).filter(isValidKey); - var len = keys.length; - var idx = -1; - var current = obj; + const parts = []; + let part = ''; - while (++idx < len) { - var key = keys[idx]; - if (idx !== len - 1) { - if (!isObject(current[key])) { - current[key] = {}; - } - current = current[key]; + 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 (isPlainObject(current[key]) && isPlainObject(val)) { - current[key] = extend({}, current[key], val); + 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 { - current[key] = val; + obj[prop] = value; } + + } else { + obj[prop] = value; } return obj; }; -function isValidKey(key) { - return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; -} +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; /***/ }), -/* 581 */ +/* 579 */ +/***/ (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'; +}; + + +/***/ }), +/* 580 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65540,8 +65585,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(582); -var has = __webpack_require__(583); +var isObject = __webpack_require__(581); +var has = __webpack_require__(582); const isUnsafeKey = key => { return key === '__proto__' || key === 'constructor' || key === 'prototype'; @@ -65583,7 +65628,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 582 */ +/* 581 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -65602,7 +65647,7 @@ function isObject(val) { /***/ }), -/* 583 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65615,8 +65660,8 @@ function isObject(val) { -const get = __webpack_require__(584); -const has = __webpack_require__(586); +const get = __webpack_require__(583); +const has = __webpack_require__(585); module.exports = function(obj, path, options) { if (isObject(obj) && (typeof path === 'string' || Array.isArray(path))) { @@ -65631,7 +65676,7 @@ function isObject(val) { /***/ }), -/* 584 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -65641,7 +65686,7 @@ function isObject(val) { * Released under the MIT License. */ -const isObject = __webpack_require__(585); +const isObject = __webpack_require__(584); module.exports = function(target, path, options) { if (!isObject(options)) { @@ -65747,7 +65792,7 @@ function isValidObject(val) { /***/ }), -/* 585 */ +/* 584 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65766,7 +65811,7 @@ module.exports = function isObject(val) { /***/ }), -/* 586 */ +/* 585 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65779,7 +65824,7 @@ module.exports = function isObject(val) { -const typeOf = __webpack_require__(539); +const typeOf = __webpack_require__(540); module.exports = function has(val) { switch (typeOf(val)) { @@ -65822,7 +65867,7 @@ module.exports = function has(val) { /***/ }), -/* 587 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65835,9 +65880,9 @@ module.exports = function has(val) { -var isObject = __webpack_require__(537); -var hasValues = __webpack_require__(588); -var get = __webpack_require__(579); +var isObject = __webpack_require__(538); +var hasValues = __webpack_require__(587); +var get = __webpack_require__(577); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -65845,7 +65890,7 @@ module.exports = function(val, prop) { /***/ }), -/* 588 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65858,8 +65903,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(539); -var isNumber = __webpack_require__(559); +var typeOf = __webpack_require__(540); +var isNumber = __webpack_require__(556); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -65912,14 +65957,14 @@ module.exports = function hasValue(val) { /***/ }), -/* 589 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(590); -var forIn = __webpack_require__(591); +var isExtendable = __webpack_require__(589); +var forIn = __webpack_require__(590); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -65983,7 +66028,7 @@ module.exports = mixinDeep; /***/ }), -/* 590 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65996,7 +66041,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(545); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -66004,7 +66049,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 591 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66027,7 +66072,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 592 */ +/* 591 */ /***/ (function(module, exports) { /*! @@ -66054,17 +66099,17 @@ module.exports = pascalcase; /***/ }), -/* 593 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var union = __webpack_require__(578); -var define = __webpack_require__(594); -var staticExtend = __webpack_require__(598); -var isObj = __webpack_require__(537); +var union = __webpack_require__(576); +var define = __webpack_require__(593); +var staticExtend = __webpack_require__(597); +var isObj = __webpack_require__(538); /** * Expose class utils @@ -66431,7 +66476,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 594 */ +/* 593 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66444,7 +66489,7 @@ cu.bubble = function(Parent, events) { -var isDescriptor = __webpack_require__(595); +var isDescriptor = __webpack_require__(594); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -66469,7 +66514,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 595 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66482,9 +66527,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(539); -var isAccessor = __webpack_require__(596); -var isData = __webpack_require__(597); +var typeOf = __webpack_require__(540); +var isAccessor = __webpack_require__(595); +var isData = __webpack_require__(596); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -66498,7 +66543,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 596 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66511,7 +66556,7 @@ module.exports = function isDescriptor(obj, key) { -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(540); // accessor descriptor properties var accessor = { @@ -66574,7 +66619,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 597 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66587,7 +66632,7 @@ module.exports = isAccessorDescriptor; -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(540); // data descriptor properties var data = { @@ -66636,7 +66681,7 @@ module.exports = isDataDescriptor; /***/ }), -/* 598 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66649,8 +66694,8 @@ module.exports = isDataDescriptor; -var copy = __webpack_require__(599); -var define = __webpack_require__(594); +var copy = __webpack_require__(598); +var define = __webpack_require__(593); var util = __webpack_require__(112); /** @@ -66733,15 +66778,15 @@ module.exports = extend; /***/ }), -/* 599 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(539); -var copyDescriptor = __webpack_require__(600); -var define = __webpack_require__(594); +var typeOf = __webpack_require__(540); +var copyDescriptor = __webpack_require__(599); +var define = __webpack_require__(593); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -66914,7 +66959,7 @@ module.exports.has = has; /***/ }), -/* 600 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67002,16 +67047,16 @@ function isObject(val) { /***/ }), -/* 601 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(602); -var define = __webpack_require__(594); -var debug = __webpack_require__(603)('snapdragon:compiler'); -var utils = __webpack_require__(609); +var use = __webpack_require__(601); +var define = __webpack_require__(593); +var debug = __webpack_require__(602)('snapdragon:compiler'); +var utils = __webpack_require__(608); /** * Create a new `Compiler` with the given `options`. @@ -67186,7 +67231,7 @@ module.exports = Compiler; /***/ }), -/* 602 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67348,7 +67393,7 @@ function define(obj, key, val) { /***/ }), -/* 603 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -67357,14 +67402,14 @@ function define(obj, key, val) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(604); + module.exports = __webpack_require__(603); } else { - module.exports = __webpack_require__(607); + module.exports = __webpack_require__(606); } /***/ }), -/* 604 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -67373,7 +67418,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(605); +exports = module.exports = __webpack_require__(604); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -67555,7 +67600,7 @@ function localstorage() { /***/ }), -/* 605 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { @@ -67571,7 +67616,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(606); +exports.humanize = __webpack_require__(605); /** * The currently active debug mode names, and names to skip. @@ -67763,7 +67808,7 @@ function coerce(val) { /***/ }), -/* 606 */ +/* 605 */ /***/ (function(module, exports) { /** @@ -67921,7 +67966,7 @@ function plural(ms, n, name) { /***/ }), -/* 607 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -67937,7 +67982,7 @@ var util = __webpack_require__(112); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(605); +exports = module.exports = __webpack_require__(604); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -68116,7 +68161,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(608); + var net = __webpack_require__(607); stream = new net.Socket({ fd: fd, readable: false, @@ -68175,13 +68220,13 @@ exports.enable(load()); /***/ }), -/* 608 */ +/* 607 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 609 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68191,7 +68236,7 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(550); +exports.extend = __webpack_require__(609); exports.SourceMap = __webpack_require__(610); exports.sourceMapResolve = __webpack_require__(621); @@ -68235,6 +68280,46 @@ exports.last = function(arr, n) { }; +/***/ }), +/* 609 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isObject = __webpack_require__(550); + +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__) { @@ -71684,7 +71769,7 @@ void (function(root, factory) { /* 623 */ /***/ (function(module, exports, __webpack_require__) { -var url = __webpack_require__(200) +var url = __webpack_require__(201) function resolveUrl(/* ...urls */) { return Array.prototype.reduce.call(arguments, function(resolved, nextUrl) { @@ -71814,23 +71899,23 @@ module.exports = function (encodedURI) { /* 626 */ /***/ (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 +// 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 /***/ }), @@ -71856,8 +71941,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(134); var path = __webpack_require__(4); -var define = __webpack_require__(594); -var utils = __webpack_require__(609); +var define = __webpack_require__(593); +var utils = __webpack_require__(608); /** * Expose `mixin()`. @@ -72006,13 +72091,13 @@ exports.comment = function(node) { "use strict"; -var use = __webpack_require__(602); +var use = __webpack_require__(601); var util = __webpack_require__(112); var Cache = __webpack_require__(630); -var define = __webpack_require__(594); -var debug = __webpack_require__(603)('snapdragon:parser'); +var define = __webpack_require__(593); +var debug = __webpack_require__(602)('snapdragon:parser'); var Position = __webpack_require__(631); -var utils = __webpack_require__(609); +var utils = __webpack_require__(608); /** * Create a new `Parser` with the given `input` and `options`. @@ -72653,7 +72738,7 @@ MapCache.prototype.del = function mapDelete(key) { "use strict"; -var define = __webpack_require__(594); +var define = __webpack_require__(593); /** * Store position for a node @@ -72674,96 +72759,8 @@ module.exports = function Position(start, parser) { "use strict"; -var isExtendable = __webpack_require__(633); -var assignSymbols = __webpack_require__(545); - -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); -} - - -/***/ }), -/* 633 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(544); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 634 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var nanomatch = __webpack_require__(635); -var extglob = __webpack_require__(647); +var nanomatch = __webpack_require__(633); +var extglob = __webpack_require__(643); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -72840,7 +72837,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 635 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72851,17 +72848,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(112); -var toRegex = __webpack_require__(529); -var extend = __webpack_require__(636); +var toRegex = __webpack_require__(530); +var extend = __webpack_require__(543); /** * Local dependencies */ -var compilers = __webpack_require__(638); -var parsers = __webpack_require__(639); -var cache = __webpack_require__(640); -var utils = __webpack_require__(642); +var compilers = __webpack_require__(634); +var parsers = __webpack_require__(635); +var cache = __webpack_require__(636); +var utils = __webpack_require__(638); var MAX_LENGTH = 1024 * 64; /** @@ -73685,95 +73682,7 @@ module.exports = nanomatch; /***/ }), -/* 636 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(637); -var assignSymbols = __webpack_require__(545); - -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); -} - - -/***/ }), -/* 637 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(544); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 638 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74119,14 +74028,14 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 639 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(546); -var toRegex = __webpack_require__(529); +var regexNot = __webpack_require__(547); +var toRegex = __webpack_require__(530); /** * Characters to use in negation regex (we want to "not" match @@ -74512,14 +74421,14 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 640 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(641))(); +module.exports = new (__webpack_require__(637))(); /***/ }), -/* 641 */ +/* 637 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74654,7 +74563,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 642 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74667,14 +74576,14 @@ var path = __webpack_require__(4); * Module dependencies */ -var isWindows = __webpack_require__(643)(); -var Snapdragon = __webpack_require__(568); -utils.define = __webpack_require__(644); -utils.diff = __webpack_require__(645); -utils.extend = __webpack_require__(636); -utils.pick = __webpack_require__(646); -utils.typeOf = __webpack_require__(539); -utils.unique = __webpack_require__(549); +var isWindows = __webpack_require__(639)(); +var Snapdragon = __webpack_require__(566); +utils.define = __webpack_require__(640); +utils.diff = __webpack_require__(641); +utils.extend = __webpack_require__(543); +utils.pick = __webpack_require__(642); +utils.typeOf = __webpack_require__(540); +utils.unique = __webpack_require__(548); /** * Returns true if the given value is effectively an empty string @@ -75040,7 +74949,7 @@ utils.unixify = function(options) { /***/ }), -/* 643 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -75068,7 +74977,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 644 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75081,8 +74990,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(537); -var isDescriptor = __webpack_require__(538); +var isobject = __webpack_require__(538); +var isDescriptor = __webpack_require__(539); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -75113,7 +75022,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 645 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75167,7 +75076,7 @@ function diffArray(one, two) { /***/ }), -/* 646 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75180,7 +75089,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(537); +var isObject = __webpack_require__(538); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -75209,7 +75118,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 647 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75219,18 +75128,18 @@ module.exports = function pick(obj, keys) { * Module dependencies */ -var extend = __webpack_require__(550); -var unique = __webpack_require__(549); -var toRegex = __webpack_require__(529); +var extend = __webpack_require__(644); +var unique = __webpack_require__(548); +var toRegex = __webpack_require__(530); /** * Local dependencies */ -var compilers = __webpack_require__(648); -var parsers = __webpack_require__(659); -var Extglob = __webpack_require__(662); -var utils = __webpack_require__(661); +var compilers = __webpack_require__(645); +var parsers = __webpack_require__(657); +var Extglob = __webpack_require__(660); +var utils = __webpack_require__(659); var MAX_LENGTH = 1024 * 64; /** @@ -75547,13 +75456,53 @@ module.exports = extglob; /***/ }), -/* 648 */ +/* 644 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isObject = __webpack_require__(550); + +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); +} + + +/***/ }), +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(649); +var brackets = __webpack_require__(646); /** * Extglob compilers @@ -75723,7 +75672,7 @@ module.exports = function(extglob) { /***/ }), -/* 649 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75733,17 +75682,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(650); -var parsers = __webpack_require__(652); +var compilers = __webpack_require__(647); +var parsers = __webpack_require__(649); /** * Module dependencies */ -var debug = __webpack_require__(654)('expand-brackets'); -var extend = __webpack_require__(550); -var Snapdragon = __webpack_require__(568); -var toRegex = __webpack_require__(529); +var debug = __webpack_require__(651)('expand-brackets'); +var extend = __webpack_require__(656); +var Snapdragon = __webpack_require__(566); +var toRegex = __webpack_require__(530); /** * Parses the given POSIX character class `pattern` and returns a @@ -75941,13 +75890,13 @@ module.exports = brackets; /***/ }), -/* 650 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(651); +var posix = __webpack_require__(648); module.exports = function(brackets) { brackets.compiler @@ -76035,7 +75984,7 @@ module.exports = function(brackets) { /***/ }), -/* 651 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76064,14 +76013,14 @@ module.exports = { /***/ }), -/* 652 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(653); -var define = __webpack_require__(594); +var utils = __webpack_require__(650); +var define = __webpack_require__(593); /** * Text regex @@ -76290,14 +76239,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 653 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(529); -var regexNot = __webpack_require__(546); +var toRegex = __webpack_require__(530); +var regexNot = __webpack_require__(547); var cached; /** @@ -76331,7 +76280,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 654 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -76340,14 +76289,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(655); + module.exports = __webpack_require__(652); } else { - module.exports = __webpack_require__(658); + module.exports = __webpack_require__(655); } /***/ }), -/* 655 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -76356,7 +76305,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(656); +exports = module.exports = __webpack_require__(653); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -76538,7 +76487,7 @@ function localstorage() { /***/ }), -/* 656 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { @@ -76554,7 +76503,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(657); +exports.humanize = __webpack_require__(654); /** * The currently active debug mode names, and names to skip. @@ -76746,7 +76695,7 @@ function coerce(val) { /***/ }), -/* 657 */ +/* 654 */ /***/ (function(module, exports) { /** @@ -76904,7 +76853,7 @@ function plural(ms, n, name) { /***/ }), -/* 658 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -76920,7 +76869,7 @@ var util = __webpack_require__(112); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(656); +exports = module.exports = __webpack_require__(653); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -77099,7 +77048,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(608); + var net = __webpack_require__(607); stream = new net.Socket({ fd: fd, readable: false, @@ -77158,15 +77107,55 @@ exports.enable(load()); /***/ }), -/* 659 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(649); -var define = __webpack_require__(660); -var utils = __webpack_require__(661); +var isObject = __webpack_require__(550); + +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); +} + + +/***/ }), +/* 657 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var brackets = __webpack_require__(646); +var define = __webpack_require__(658); +var utils = __webpack_require__(659); /** * Characters to use in text regex (we want to "not" match @@ -77321,7 +77310,7 @@ module.exports = parsers; /***/ }), -/* 660 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77334,7 +77323,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(538); +var isDescriptor = __webpack_require__(539); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -77359,14 +77348,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 661 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(546); -var Cache = __webpack_require__(641); +var regex = __webpack_require__(547); +var Cache = __webpack_require__(637); /** * Utils @@ -77435,7 +77424,7 @@ utils.createRegex = function(str) { /***/ }), -/* 662 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77445,16 +77434,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(568); -var define = __webpack_require__(660); -var extend = __webpack_require__(550); +var Snapdragon = __webpack_require__(566); +var define = __webpack_require__(658); +var extend = __webpack_require__(644); /** * Local dependencies */ -var compilers = __webpack_require__(648); -var parsers = __webpack_require__(659); +var compilers = __webpack_require__(645); +var parsers = __webpack_require__(657); /** * Customize Snapdragon parser and renderer @@ -77520,16 +77509,16 @@ module.exports = Extglob; /***/ }), -/* 663 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(647); -var nanomatch = __webpack_require__(635); -var regexNot = __webpack_require__(546); -var toRegex = __webpack_require__(529); +var extglob = __webpack_require__(643); +var nanomatch = __webpack_require__(633); +var regexNot = __webpack_require__(547); +var toRegex = __webpack_require__(530); var not; /** @@ -77610,14 +77599,14 @@ function textRegex(pattern) { /***/ }), -/* 664 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(641))(); +module.exports = new (__webpack_require__(637))(); /***/ }), -/* 665 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77630,13 +77619,13 @@ var path = __webpack_require__(4); * Module dependencies */ -var Snapdragon = __webpack_require__(568); -utils.define = __webpack_require__(666); -utils.diff = __webpack_require__(645); -utils.extend = __webpack_require__(632); -utils.pick = __webpack_require__(646); -utils.typeOf = __webpack_require__(539); -utils.unique = __webpack_require__(549); +var Snapdragon = __webpack_require__(566); +utils.define = __webpack_require__(664); +utils.diff = __webpack_require__(641); +utils.extend = __webpack_require__(543); +utils.pick = __webpack_require__(642); +utils.typeOf = __webpack_require__(540); +utils.unique = __webpack_require__(548); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -77933,7 +77922,7 @@ utils.unixify = function(options) { /***/ }), -/* 666 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77946,8 +77935,8 @@ utils.unixify = function(options) { -var isobject = __webpack_require__(537); -var isDescriptor = __webpack_require__(538); +var isobject = __webpack_require__(538); +var isDescriptor = __webpack_require__(539); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -77978,97 +77967,97 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 667 */ +/* 665 */ /***/ (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__(668); -var reader_1 = __webpack_require__(681); -var fs_stream_1 = __webpack_require__(685); -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; + +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__(666); +var reader_1 = __webpack_require__(679); +var fs_stream_1 = __webpack_require__(683); +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; /***/ }), -/* 668 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(669); -const readdirAsync = __webpack_require__(677); -const readdirStream = __webpack_require__(680); +const readdirSync = __webpack_require__(667); +const readdirAsync = __webpack_require__(675); +const readdirStream = __webpack_require__(678); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -78152,7 +78141,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 669 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78160,11 +78149,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(670); +const DirectoryReader = __webpack_require__(668); let syncFacade = { - fs: __webpack_require__(675), - forEach: __webpack_require__(676), + fs: __webpack_require__(673), + forEach: __webpack_require__(674), sync: true }; @@ -78193,18 +78182,18 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 670 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const Readable = __webpack_require__(138).Readable; -const EventEmitter = __webpack_require__(156).EventEmitter; +const EventEmitter = __webpack_require__(157).EventEmitter; const path = __webpack_require__(4); -const normalizeOptions = __webpack_require__(671); -const stat = __webpack_require__(673); -const call = __webpack_require__(674); +const normalizeOptions = __webpack_require__(669); +const stat = __webpack_require__(671); +const call = __webpack_require__(672); /** * Asynchronously reads the contents of a directory and streams the results @@ -78580,14 +78569,14 @@ module.exports = DirectoryReader; /***/ }), -/* 671 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(672); +const globToRegExp = __webpack_require__(670); module.exports = normalizeOptions; @@ -78764,7 +78753,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 672 */ +/* 670 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -78901,13 +78890,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 673 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(674); +const call = __webpack_require__(672); module.exports = stat; @@ -78982,7 +78971,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 674 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79043,14 +79032,14 @@ function callOnce (fn) { /***/ }), -/* 675 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const call = __webpack_require__(674); +const call = __webpack_require__(672); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -79114,7 +79103,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 676 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79143,7 +79132,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 677 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79151,12 +79140,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(678); -const DirectoryReader = __webpack_require__(670); +const maybe = __webpack_require__(676); +const DirectoryReader = __webpack_require__(668); let asyncFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(679), + forEach: __webpack_require__(677), async: true }; @@ -79198,7 +79187,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 678 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79225,7 +79214,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 679 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79261,7 +79250,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 680 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79269,11 +79258,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(670); +const DirectoryReader = __webpack_require__(668); let streamFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(679), + forEach: __webpack_require__(677), async: true }; @@ -79293,373 +79282,373 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 681 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(4); -var deep_1 = __webpack_require__(682); -var entry_1 = __webpack_require__(684); -var pathUtil = __webpack_require__(683); -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; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(4); +var deep_1 = __webpack_require__(680); +var entry_1 = __webpack_require__(682); +var pathUtil = __webpack_require__(681); +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; /***/ }), -/* 682 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(683); -var patternUtils = __webpack_require__(526); -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; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pathUtils = __webpack_require__(681); +var patternUtils = __webpack_require__(527); +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; /***/ }), -/* 683 */ +/* 681 */ /***/ (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; + +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; /***/ }), -/* 684 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(683); -var patternUtils = __webpack_require__(526); -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; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pathUtils = __webpack_require__(681); +var patternUtils = __webpack_require__(527); +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; /***/ }), -/* 685 */ +/* 683 */ /***/ (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__(686); -var fs_1 = __webpack_require__(690); -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; + +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__(684); +var fs_1 = __webpack_require__(688); +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; /***/ }), -/* 686 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(687); -const statProvider = __webpack_require__(689); +const optionsManager = __webpack_require__(685); +const statProvider = __webpack_require__(687); /** * Asynchronous API. */ @@ -79690,13 +79679,13 @@ exports.statSync = statSync; /***/ }), -/* 687 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(688); +const fsAdapter = __webpack_require__(686); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -79709,7 +79698,7 @@ exports.prepare = prepare; /***/ }), -/* 688 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79732,7 +79721,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 689 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79784,318 +79773,318 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 690 */ +/* 688 */ /***/ (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; + +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; /***/ }), -/* 691 */ +/* 689 */ /***/ (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__(668); -var reader_1 = __webpack_require__(681); -var fs_stream_1 = __webpack_require__(685); -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; + +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__(666); +var reader_1 = __webpack_require__(679); +var fs_stream_1 = __webpack_require__(683); +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; /***/ }), -/* 692 */ +/* 690 */ /***/ (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__(668); -var reader_1 = __webpack_require__(681); -var fs_sync_1 = __webpack_require__(693); -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; + +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__(666); +var reader_1 = __webpack_require__(679); +var fs_sync_1 = __webpack_require__(691); +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; /***/ }), -/* 693 */ +/* 691 */ /***/ (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__(686); -var fs_1 = __webpack_require__(690); -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; + +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__(684); +var fs_1 = __webpack_require__(688); +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; /***/ }), -/* 694 */ +/* 692 */ /***/ (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; + +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; /***/ }), -/* 695 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(300); -/** - * 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; + +Object.defineProperty(exports, "__esModule", { value: true }); +var merge2 = __webpack_require__(301); +/** + * 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; /***/ }), -/* 696 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(697); +const pathType = __webpack_require__(695); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -80161,13 +80150,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 697 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const pify = __webpack_require__(698); +const pify = __webpack_require__(696); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -80210,7 +80199,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 698 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80301,17 +80290,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 699 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(522); -const gitIgnore = __webpack_require__(700); -const pify = __webpack_require__(233); -const slash = __webpack_require__(701); +const fastGlob = __webpack_require__(523); +const gitIgnore = __webpack_require__(698); +const pify = __webpack_require__(234); +const slash = __webpack_require__(699); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -80409,7 +80398,7 @@ module.exports.sync = options => { /***/ }), -/* 700 */ +/* 698 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -80878,7 +80867,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 701 */ +/* 699 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80896,7 +80885,7 @@ module.exports = input => { /***/ }), -/* 702 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80909,7 +80898,7 @@ module.exports = input => { -var isGlob = __webpack_require__(703); +var isGlob = __webpack_require__(701); module.exports = function hasGlob(val) { if (val == null) return false; @@ -80929,7 +80918,7 @@ module.exports = function hasGlob(val) { /***/ }), -/* 703 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -80939,7 +80928,7 @@ module.exports = function hasGlob(val) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(311); +var isExtglob = __webpack_require__(312); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -80960,17 +80949,17 @@ module.exports = function isGlob(str) { /***/ }), -/* 704 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(134); -const pEvent = __webpack_require__(705); -const CpFileError = __webpack_require__(708); -const fs = __webpack_require__(710); -const ProgressEmitter = __webpack_require__(713); +const pEvent = __webpack_require__(703); +const CpFileError = __webpack_require__(706); +const fs = __webpack_require__(708); +const ProgressEmitter = __webpack_require__(711); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -81084,12 +81073,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 705 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(706); +const pTimeout = __webpack_require__(704); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -81382,13 +81371,13 @@ module.exports.TimeoutError = pTimeout.TimeoutError; /***/ }), -/* 706 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(707); +const pFinally = __webpack_require__(705); class TimeoutError extends Error { constructor(message) { @@ -81446,7 +81435,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 707 */ +/* 705 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81468,12 +81457,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 708 */ +/* 706 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(709); +const NestedError = __webpack_require__(707); class CpFileError extends NestedError { constructor(message, nested) { @@ -81487,7 +81476,7 @@ module.exports = CpFileError; /***/ }), -/* 709 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(112).inherits; @@ -81543,16 +81532,16 @@ module.exports = NestedError; /***/ }), -/* 710 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(112); const fs = __webpack_require__(133); -const makeDir = __webpack_require__(711); -const pEvent = __webpack_require__(705); -const CpFileError = __webpack_require__(708); +const makeDir = __webpack_require__(709); +const pEvent = __webpack_require__(703); +const CpFileError = __webpack_require__(706); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -81649,7 +81638,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 711 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81657,7 +81646,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(134); const path = __webpack_require__(4); const {promisify} = __webpack_require__(112); -const semver = __webpack_require__(712); +const semver = __webpack_require__(710); const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); @@ -81812,7 +81801,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 712 */ +/* 710 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -83414,12 +83403,12 @@ function coerce (version, options) { /***/ }), -/* 713 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const EventEmitter = __webpack_require__(156); +const EventEmitter = __webpack_require__(157); const written = new WeakMap(); @@ -83455,7 +83444,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 714 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83501,12 +83490,12 @@ exports.default = module.exports; /***/ }), -/* 715 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(716); +const pMap = __webpack_require__(714); const pFilter = async (iterable, filterer, options) => { const values = await pMap( @@ -83523,7 +83512,7 @@ module.exports.default = pFilter; /***/ }), -/* 716 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83602,12 +83591,12 @@ module.exports.default = pMap; /***/ }), -/* 717 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(709); +const NestedError = __webpack_require__(707); class CpyError extends NestedError { constructor(message, nested) { diff --git a/packages/osd-pm/package.json b/packages/osd-pm/package.json index 5f50dc858b13..66a529bc7b62 100644 --- a/packages/osd-pm/package.json +++ b/packages/osd-pm/package.json @@ -20,7 +20,6 @@ "@babel/preset-typescript": "^7.16.5", "@node-rs/xxhash": "^1.3.0", "@types/cmd-shim": "^2.0.0", - "@types/cpy": "^5.1.0", "@types/dedent": "^0.7.0", "@types/getopts": "^2.0.1", "@types/glob": "^7.1.3", diff --git a/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/package.json b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/package.json new file mode 100644 index 000000000000..f1c6f179d502 --- /dev/null +++ b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/package.json @@ -0,0 +1,14 @@ +{ + "name": "opensearch-dashboards", + "version": "1.0.0", + "private": "true", + "dependencies": { + "foo": "1.0.0", + "@scoped/baz": "file:../other-plugins/baz" + }, + "workspaces": { + "packages": [ + "packages/*" + ] + } +} diff --git a/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/packages/bar/package.json b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/packages/bar/package.json new file mode 100644 index 000000000000..62eba57e2481 --- /dev/null +++ b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/packages/bar/package.json @@ -0,0 +1,8 @@ +{ + "name": "bar", + "version": "1.0.0", + "dependencies": { + "foo": "1.0.0", + "@scoped/baz": "file:../../../other-plugins/baz" + } +} diff --git a/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/packages/foo/package.json b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/packages/foo/package.json new file mode 100644 index 000000000000..da86787ad3ec --- /dev/null +++ b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/packages/foo/package.json @@ -0,0 +1,4 @@ +{ + "name": "foo", + "version": "1.0.0" +} diff --git a/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/yarn.lock b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/yarn.lock new file mode 100644 index 000000000000..3d2c45192493 --- /dev/null +++ b/packages/osd-pm/src/utils/__fixtures__/opensearch-dashboards-dev/yarn.lock @@ -0,0 +1,6 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@scoped/baz@file:../other-plugins/baz": + version "1.0.0" diff --git a/packages/osd-pm/src/utils/yarn_lock.test.ts b/packages/osd-pm/src/utils/yarn_lock.test.ts new file mode 100644 index 000000000000..5f3d1ae0d27a --- /dev/null +++ b/packages/osd-pm/src/utils/yarn_lock.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { resolve } from 'path'; +import { OpenSearchDashboards } from './opensearch_dashboards'; +import { readYarnLock } from './yarn_lock'; + +const rootPath = resolve(`${__dirname}/__fixtures__/opensearch-dashboards-dev`); + +const linkedDepmarker = 'file:'; +const linkedDepmarkerLength = linkedDepmarker.length; + +describe('#readYarnLock', () => { + it('includes an entry with the absolute path to a linked dependency', async () => { + const devProject = await OpenSearchDashboards.loadFrom(rootPath); + const { allDependencies } = devProject.getProject('opensearch-dashboards'); + const expectedObject = Object.keys(allDependencies).reduce( + (accumulator: { [key: string]: any }, key) => { + if (allDependencies[key].startsWith('file:')) { + accumulator[ + key + + '@file:' + + resolve( + devProject.getAbsolute(), + allDependencies[key].substring(linkedDepmarkerLength) + ) + ] = expect.any(Object); + } + return accumulator; + }, + {} + ); + + const result = await readYarnLock(devProject); + + expect(result).toMatchObject(expectedObject); + }); +}); diff --git a/packages/osd-pm/src/utils/yarn_lock.ts b/packages/osd-pm/src/utils/yarn_lock.ts index cdd3639626d0..b83b17bb61e6 100644 --- a/packages/osd-pm/src/utils/yarn_lock.ts +++ b/packages/osd-pm/src/utils/yarn_lock.ts @@ -30,6 +30,8 @@ // @ts-expect-error published types are worthless import { parse as parseLockfile } from '@yarnpkg/lockfile'; +import { standardize } from '@osd/cross-platform'; +import { resolve, isAbsolute } from 'path'; import { readFile } from '../utils/fs'; import { OpenSearchDashboards } from '../utils/opensearch_dashboards'; @@ -62,7 +64,7 @@ export async function readYarnLock(osd: OpenSearchDashboards): Promise const yarnLock = parseLockfile(contents); if (yarnLock.type === 'success') { - return yarnLock.object; + return fixFileLinks(yarnLock.object, osd.getAbsolute()); } throw new Error('unable to read yarn.lock file, please run `yarn osd bootstrap`'); @@ -75,6 +77,33 @@ export async function readYarnLock(osd: OpenSearchDashboards): Promise return {}; } +/** + * Converts relative `file:` paths to absolute paths + * Yarn parsing method converts all file URIs to relative paths and this + * breaks the single-version requirement as dependencies to the same path + * would differ in their URIs across OSD and packages. + */ +function fixFileLinks(yarnLock: YarnLock, projectRoot: string): YarnLock { + const fileLinkDelimiter = '@file:'; + + const linkedKeys = Object.keys(yarnLock).filter((key) => key.includes(fileLinkDelimiter)); + + if (linkedKeys.length === 0) return yarnLock; + + const updatedYarnLock = { ...yarnLock }; + for (const key of linkedKeys) { + const [keyName, keyPath, ...rest] = key.split(fileLinkDelimiter); + if (!isAbsolute(keyPath)) { + const updatedKeyName = [keyName, standardize(resolve(projectRoot, keyPath)), ...rest].join( + fileLinkDelimiter + ); + updatedYarnLock[updatedKeyName] = updatedYarnLock[key]; + } + } + + return updatedYarnLock; +} + /** * Get a list of the absolute dependencies of this project, as resolved * in the yarn.lock file, does not include other projects in the workspace diff --git a/packages/osd-stylelint-config/.stylelintrc.js b/packages/osd-stylelint-config/.stylelintrc.js new file mode 100644 index 000000000000..aa06f1a72f08 --- /dev/null +++ b/packages/osd-stylelint-config/.stylelintrc.js @@ -0,0 +1,40 @@ +/* + * 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. + */ + +module.exports = { + plugins: [ + '@osd/stylelint-plugin-stylelint', + ], + + rules: { + '@osd/stylelint/no_restricted_properties': [ + { + config: "./../../../osd-stylelint-config/config/restricted_properties.json" + }, + { + severity: "error" + } + ], + '@osd/stylelint/no_modifying_global_selectors': [ + { + config: "./../../../osd-stylelint-config/config/global_selectors.json" + }, + { + severity: "error" + } + ], + '@osd/stylelint/no_custom_colors': [ + { + config: './../../../osd-stylelint-config/config/colors.json' + }, + ] + } +} diff --git a/packages/osd-stylelint-config/README.md b/packages/osd-stylelint-config/README.md new file mode 100644 index 000000000000..68d7354626f3 --- /dev/null +++ b/packages/osd-stylelint-config/README.md @@ -0,0 +1,45 @@ +# osd-stylelint-config + +The Stylelint config used by OpenSearch Dashboards. This package is created to enable the modification of rules with the JSON files in `config/` and any consumer of the `@osd/stylelint-plugin-stylelint` can just extend this config within its `.stylelintrc`. + +The ideal state being that this package is maintained externally from the OpenSearch Dashboards repo so that the configs can be modified with rules without being blocked by processes within OpenSearch Dashboards. + +Issue: +https://github.com/opensearch-project/oui/issues/845 + +## Usage + +To use this stylelint config, just install the peer dependencies and reference it +in your `.stylelintrc`: + +```javascript +{ + extends: [ + '@osd/stylelint-config' + ] +} +``` + +This JSON configs that are sent through the compliance engine are expected to follow the schema: + +```json +{ + "cssProperty": { + "regexOfSelector": [ + { + "approved": "OUICompliantValue1", + "rejected": [ + "OUIViolationValue1", + "OUIViolationValue2", + ] + }, + { + "approved": "OUICompliantValue2", + "rejected": [ + "OUIViolationValue3" + ] + } + ] + } +} +``` diff --git a/packages/osd-stylelint-config/config/colors.json b/packages/osd-stylelint-config/config/colors.json new file mode 100644 index 000000000000..70728fa1227e --- /dev/null +++ b/packages/osd-stylelint-config/config/colors.json @@ -0,0 +1,18 @@ +{ + "background-color": { + "buttonTODOTHISANEXAMPLE": [ + { + "approved": "$euiColorPrimary", + "rejected": [ + "blueTODOTHISANEXAMPLE" + ] + }, + { + "approved": "$euiColorWarning", + "rejected": [ + "redTODOTHISANEXAMPLE" + ] + } + ] + } +} diff --git a/packages/osd-stylelint-config/config/global_selectors.json b/packages/osd-stylelint-config/config/global_selectors.json new file mode 100644 index 000000000000..99b2db2dfb4f --- /dev/null +++ b/packages/osd-stylelint-config/config/global_selectors.json @@ -0,0 +1,30 @@ +{ + "#opensearch-dashboards-body": { + "approved": [ + "src/core/public/rendering/_base.scss" + ] + }, + ".app-wrapper": { + "approved": [ + "src/core/public/rendering/_base.scss" + ] + }, + "/\\.[eo]ui/": { + "approved": [ + "examples/expressions_example/public/index.scss", + "src/core/public/styles/_base.scss", + "src/plugins/vis_default_editor/public/_sidebar.scss", + "src/core/public/core_app/styles/_mixins.scss", + "src/core/public/chrome/ui/header/_index.scss", + "src/core/public/chrome/ui/header/header_breadcrumbs.scss", + "src/core/public/chrome/ui/header/home_loader.scss", + "src/plugins/data/public/ui/filter_bar/_global_filter_item.scss", + "src/plugins/home/public/application/components/_synopsis.scss", + "src/plugins/vis_builder/public/application/components/searchable_dropdown.scss", + "src/plugins/vis_builder/public/application/components/side_nav.scss", + "packages/osd-ui-framework/src/components/button/button_group/_button_group.scss", + "src/plugins/discover_legacy/public/application/components/sidebar/discover_sidebar.scss", + "src/plugins/discover_legacy/public/application/angular/doc_table/components/table_row/_open.scss" + ] + } +} \ No newline at end of file diff --git a/packages/osd-stylelint-config/config/restricted_properties.json b/packages/osd-stylelint-config/config/restricted_properties.json new file mode 100644 index 000000000000..cf93f199ad07 --- /dev/null +++ b/packages/osd-stylelint-config/config/restricted_properties.json @@ -0,0 +1,18 @@ +{ + "font-family": { + "approved": [ + "src/plugins/discover_legacy/public/application/_discover.scss", + "src/plugins/maps_legacy/public/map/_leaflet_overrides.scss", + "src/plugins/maps_legacy/public/map/_legend.scss", + "src/plugins/opensearch_dashboards_legacy/public/font_awesome/font_awesome.scss", + "src/plugins/opensearch_dashboards_react/public/markdown/_markdown.scss", + "packages/osd-ui-framework/src/components/tool_bar/_tool_bar_search.scss", + "packages/osd-ui-framework/src/global_styling/mixins/_global_mixins.scss", + "src/plugins/data/public/ui/typeahead/_suggestion.scss", + "src/plugins/vis_type_timeseries/public/application/components/_error.scss", + "packages/osd-ui-framework/src/components/form/check_box/_check_box.scss", + "src/plugins/discover_legacy/public/application/components/doc_viewer/doc_viewer.scss", + "src/plugins/discover/public/application/components/doc_viewer/doc_viewer.scss" + ] + } +} \ No newline at end of file diff --git a/packages/osd-stylelint-config/package.json b/packages/osd-stylelint-config/package.json new file mode 100644 index 000000000000..750a1bf207d8 --- /dev/null +++ b/packages/osd-stylelint-config/package.json @@ -0,0 +1,15 @@ +{ + "name": "@osd/stylelint-config", + "version": "1.0.0", + "description": "The stylelint config used by OpenSearch Dashboards", + "main": ".stylelintrc.js", + "private": true, + "license": "Apache-2.0", + "opensearchDashboards": { + "devOnly": true + }, + "peerDependencies": { + "@osd/stylelint-plugin-stylelint": "1.0.0", + "stylelint": "^14.5.2" + } +} diff --git a/packages/osd-stylelint-plugin-stylelint/README.md b/packages/osd-stylelint-plugin-stylelint/README.md new file mode 100644 index 000000000000..8c9f0a1d6d4b --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/README.md @@ -0,0 +1,68 @@ +# Custom Stylelint rules for OpenSearch Dashboards + +This package contains custom Stylelint rules used for OpenSearch Dashboards development. Rules are defined in `src/rules` and are the actual logic of the custom rules which are built around parsing a JSON config file passed in and applying the rules defined within there. + +This package can work with `@osd/stylelint-config` which houses the JSON config files to be passed into this plugin. The goal being to seperate out OUI compliance rules which can be modified by anyone versus the actual OUI compliance engine which should be only modified by developers. + +## Audit styles that are related to custom rules + +Setting: +``` +export OUI_AUDIT_ENABLED=true +``` + +Enables the ability to capture styling that potentially can be subject to compliance when there is a rule that interacts with the styling. + +For example, if a style attempts to set a button to have a `background-color: $incorrectVariable()` and the JSON config passed to the compliance engine does not explicitly reject the `$incorrectVariable()` being applied to a button's background color then the linter will pass. But it will output this if the environment variable is set to `true`. + +The goal being that setting this environment variable to output a list that can then be added to the JSON config which we can feed back into the compliance engine. + +## Supported config formats + +Currently, this package supports 2 formats for config: file based and value based. + +### File based config + +Sample: +```json +{ + "#global-id": { + "approved": [ + "src/foo/bar.scss" + ] + }, + ".component-class": { + "approved": [ + "src/bar/baz.scss" + ] + } +} +``` + +Allows specifying a selector, such as a CSS selector (class, id, etc.), to be caught by the rule, as well as an allowlist of files where the selector is allowed. + +### Value based config + +Sample: +```json +{ + "color": { + "button": [ + { + "approved": "$primaryColor", + "rejected": [ + "blue" + ] + }, + { + "approved": "$errorColor", + "rejected": [ + "red" + ] + } + ] + } +} +``` + +Allows specifying multiple selectors for finding values. Supports complex configurations of variants with both an approved value and set of rejected values. diff --git a/packages/osd-stylelint-plugin-stylelint/package.json b/packages/osd-stylelint-plugin-stylelint/package.json new file mode 100644 index 000000000000..49947331fb59 --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/package.json @@ -0,0 +1,23 @@ +{ + "name": "@osd/stylelint-plugin-stylelint", + "main": "./target/index.js", + "types": "./target/index.d.ts", + "version": "1.0.0", + "private": true, + "license": "Apache-2.0", + "scripts": { + "build": "tsc", + "osd:bootstrap": "yarn build" + }, + "opensearchDashboards": { + "devOnly": true + }, + "peerDependencies": { + "postcss": "^8.4.12", + "stylelint": "^14.5.2" + }, + "devDependencies": { + "typescript": "4.0.2", + "tsd": "^0.21.0" + } +} diff --git a/packages/osd-stylelint-plugin-stylelint/src/index.ts b/packages/osd-stylelint-plugin-stylelint/src/index.ts new file mode 100644 index 000000000000..db919d008f99 --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/index.ts @@ -0,0 +1,22 @@ +/* + * 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 stylelint from 'stylelint'; +import rules from './rules'; + +export const NAMESPACE = '@osd/stylelint'; + +const rulesPlugins = Object.keys(rules).map((ruleName: string) => { + return stylelint.createPlugin(`${NAMESPACE}/${ruleName}`, rules[ruleName]); +}); + +// eslint-disable-next-line import/no-default-export +export default rulesPlugins; diff --git a/packages/osd-stylelint-plugin-stylelint/src/rules/index.ts b/packages/osd-stylelint-plugin-stylelint/src/rules/index.ts new file mode 100644 index 000000000000..6dc26fe93f26 --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/rules/index.ts @@ -0,0 +1,21 @@ +/* + * 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 noRestrictedProperties from './no_restricted_properties'; +import noCustomColors from './no_custom_colors'; +import noModifyingGlobalSelectors from './no_modifying_global_selectors'; + +// eslint-disable-next-line import/no-default-export +export default { + no_custom_colors: noCustomColors, + no_modifying_global_selectors: noModifyingGlobalSelectors, + no_restricted_properties: noRestrictedProperties, +}; diff --git a/packages/osd-stylelint-plugin-stylelint/src/rules/no_custom_colors/index.ts b/packages/osd-stylelint-plugin-stylelint/src/rules/no_custom_colors/index.ts new file mode 100644 index 000000000000..9a8fab66c509 --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/rules/no_custom_colors/index.ts @@ -0,0 +1,108 @@ +/* + * 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 stylelint from 'stylelint'; +import { NAMESPACE } from '../..'; +import { + ComplianceEngine, + getTrackedMessage, + getUntrackedMessage, + getNotCompliantMessage, + getRulesFromConfig, + getColorPropertyParent, + isValidOptions, + ValueBasedConfig, +} from '../../utils'; + +const isOuiAuditEnabled = Boolean(process.env.OUI_AUDIT_ENABLED); + +const { ruleMessages, report } = stylelint.utils; +const engine = ComplianceEngine.default; + +const ruleName = 'no_custom_colors'; +const messages = ruleMessages(ruleName, { + expected: (message) => `${message}`, +}); + +const ruleFunction: stylelint.Rule = ( + primaryOption: Record, + secondaryOptionObject: Record, + context +) => { + return (postcssRoot, postcssResult) => { + const validOptions = isValidOptions(postcssResult, ruleName, primaryOption); + if (!validOptions) { + return; + } + + const rules: ValueBasedConfig = getRulesFromConfig(primaryOption.config); + + const isAutoFixing = Boolean(context.fix); + + postcssRoot.walkDecls((decl) => { + const parent = getColorPropertyParent(decl); + if (!parent) { + return; + } + + let shouldReport = false; + + const nodeInfo = { + selector: parent.selector, + prop: decl.prop, + value: decl.value, + }; + + const reportInfo = { + ruleName: `${NAMESPACE}/${ruleName}`, + result: postcssResult, + node: decl, + message: '', + }; + + if (isOuiAuditEnabled && !engine.isTracked(rules, nodeInfo)) { + reportInfo.message = messages.expected(getUntrackedMessage(nodeInfo)); + report(reportInfo); + return; + } + + const ruleObject = engine.getComplianceRule(rules, nodeInfo); + + if (!ruleObject) { + if (isOuiAuditEnabled) { + reportInfo.message = messages.expected(getTrackedMessage(nodeInfo)); + report(reportInfo); + } + return; + } + + shouldReport = !ruleObject.isComplaint; + + if (shouldReport && isAutoFixing && ruleObject.expected) { + decl.value = ruleObject.expected; + return; + } + + if (!shouldReport) { + return; + } + + reportInfo.message = messages.expected(getNotCompliantMessage(ruleObject.message)); + report(reportInfo); + }); + }; +}; + +ruleFunction.ruleName = ruleName; +ruleFunction.messages = messages; + +// eslint-disable-next-line import/no-default-export +export default ruleFunction; diff --git a/packages/osd-stylelint-plugin-stylelint/src/rules/no_modifying_global_selectors/index.ts b/packages/osd-stylelint-plugin-stylelint/src/rules/no_modifying_global_selectors/index.ts new file mode 100644 index 000000000000..d58e7819688f --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/rules/no_modifying_global_selectors/index.ts @@ -0,0 +1,93 @@ +/* + * 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 stylelint from 'stylelint'; +import { NAMESPACE } from '../..'; +import { + getNotCompliantMessage, + getRulesFromConfig, + isValidOptions, + getRuleFromConfig, + FileBasedConfig, +} from '../../utils'; + +const { ruleMessages, report } = stylelint.utils; + +const ruleName = 'no_modifying_global_selectors'; +const messages = ruleMessages(ruleName, { + expected: (message) => `${message}`, +}); + +const ruleFunction: stylelint.Rule = ( + primaryOption: Record, + secondaryOptionObject: Record, + context +) => { + return (postcssRoot, postcssResult) => { + const validOptions = isValidOptions(postcssResult, ruleName, primaryOption); + if (!validOptions) { + return; + } + + const rules: FileBasedConfig = getRulesFromConfig(primaryOption.config); + + const isAutoFixing = Boolean(context.fix); + + postcssRoot.walkRules((rule) => { + const selectorRule = getRuleFromConfig(rules, rule.selector); + if (!selectorRule) { + return; + } + + let shouldReport = false; + + const file = postcssRoot.source?.input.file; + if (!file) { + return; + } + + const approvedFiles = selectorRule.approved; + + const reportInfo = { + ruleName: `${NAMESPACE}/${ruleName}`, + result: postcssResult, + node: rule, + message: '', + }; + + if (approvedFiles) { + shouldReport = !approvedFiles.some((inspectedFile) => { + return file.includes(inspectedFile); + }); + } + + if (shouldReport && isAutoFixing) { + rule.remove(); + return; + } + + if (!shouldReport) { + return; + } + + reportInfo.message = messages.expected( + getNotCompliantMessage(`Modifying global selector "${rule.selector}" not allowed.`) + ); + report(reportInfo); + }); + }; +}; + +ruleFunction.ruleName = ruleName; +ruleFunction.messages = messages; + +// eslint-disable-next-line import/no-default-export +export default ruleFunction; diff --git a/packages/osd-stylelint-plugin-stylelint/src/rules/no_restricted_properties/index.ts b/packages/osd-stylelint-plugin-stylelint/src/rules/no_restricted_properties/index.ts new file mode 100644 index 000000000000..9da587545b1d --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/rules/no_restricted_properties/index.ts @@ -0,0 +1,87 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import stylelint from 'stylelint'; +import { NAMESPACE } from '../..'; +import { + getNotCompliantMessage, + getRuleFromConfig, + getRulesFromConfig, + isValidOptions, + FileBasedConfig, +} from '../../utils'; + +const { ruleMessages, report } = stylelint.utils; + +const ruleName = 'no_restricted_properties'; +const messages = ruleMessages(ruleName, { + expected: (message) => `${message}`, +}); + +const ruleFunction: stylelint.Rule = ( + primaryOption: Record, + secondaryOptionObject: Record, + context +) => { + return (postcssRoot, postcssResult) => { + const validOptions = isValidOptions(postcssResult, ruleName, primaryOption); + if (!validOptions) { + return; + } + + const rules: FileBasedConfig = getRulesFromConfig(primaryOption.config); + + const isAutoFixing = Boolean(context.fix); + + postcssRoot.walkDecls((decl) => { + const propertyRule = getRuleFromConfig(rules, decl.prop); + if (!propertyRule) { + return; + } + + let shouldReport = false; + + const file = postcssRoot.source?.input.file; + if (!file) { + return; + } + + const approvedFiles = propertyRule.approved; + + const reportInfo = { + ruleName: `${NAMESPACE}/${ruleName}`, + result: postcssResult, + node: decl, + message: '', + }; + + if (approvedFiles) { + shouldReport = !approvedFiles.some((inspectedFile) => { + return file.includes(inspectedFile); + }); + } + + if (shouldReport && isAutoFixing) { + decl.remove(); + return; + } + + if (!shouldReport) { + return; + } + + reportInfo.message = messages.expected( + getNotCompliantMessage(`Usage of property "${decl.prop}" is not allowed.`) + ); + report(reportInfo); + }); + }; +}; + +ruleFunction.ruleName = ruleName; +ruleFunction.messages = messages; + +// eslint-disable-next-line import/no-default-export +export default ruleFunction; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/compliance_engine.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/compliance_engine.ts new file mode 100644 index 000000000000..7b95e94e536c --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/compliance_engine.ts @@ -0,0 +1,79 @@ +/* + * 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 { ValueBasedConfig } from './get_rules_from_config'; + +export interface ComplianceRule { + isComplaint: boolean; + actual: string; + expected: string | undefined; + message: string; +} + +const getRule = (rules: ValueBasedConfig, nodeInfo: { selector: string; prop: string }) => { + const rule = rules[nodeInfo.prop]; + if (!rule) { + return undefined; + } + + if (!nodeInfo.selector) { + return undefined; + } + + const ruleKey = Object.keys(rule).find((key) => { + const regex = new RegExp(key, 'gi'); + return nodeInfo.selector.match(regex); + }); + + if (!ruleKey) { + return undefined; + } + + return rule[ruleKey]; +}; + +const isTracked = (rules: ValueBasedConfig, nodeInfo: { selector: string; prop: string }) => { + return getRule(rules, nodeInfo) !== undefined; +}; + +const getComplianceRule = ( + rules: ValueBasedConfig, + nodeInfo: { selector: string; prop: string; value: string } +): ComplianceRule | undefined => { + const rule = getRule(rules, nodeInfo); + + if (!rule) { + return undefined; + } + + const ruleObject = rule.find((object) => { + if (object.approved?.includes(nodeInfo.value) || object.rejected?.includes(nodeInfo.value)) { + return object; + } + }); + + if (!ruleObject) { + return undefined; + } + + return { + isComplaint: !ruleObject.rejected?.includes(nodeInfo.value), + actual: nodeInfo.value, + expected: ruleObject.approved, + message: `${nodeInfo.selector} expected: ${ruleObject.approved} - actual: ${nodeInfo.value}`, + }; +}; + +// eslint-disable-next-line import/no-default-export +export default { + isTracked, + getComplianceRule, +}; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/extract_regex.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/extract_regex.ts new file mode 100644 index 000000000000..937b486ad940 --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/extract_regex.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const extractRegex = (value: string) => { + if (!value.startsWith('/')) { + return undefined; + } + + const split = value.split('/'); + split.shift(); + + const flags = split.pop(); + if (split.length === 0) { + return undefined; + } + + const pattern = split.join('/'); + + return new RegExp(pattern, flags); +}; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/get_message.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/get_message.ts new file mode 100644 index 000000000000..65e236aaffad --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/get_message.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 getUntrackedMessage = (nodeInfo: { selector: string; prop: string; value: string }) => + `Untracked: "${nodeInfo.selector}.${nodeInfo.prop}: ${nodeInfo.value}"`; + +export const getTrackedMessage = (nodeInfo: { selector: string; prop: string; value: string }) => + `Tracked but missing approval: "${nodeInfo.selector}.${nodeInfo.prop}: ${nodeInfo.value}"`; + +export const getNotCompliantMessage = (message: string) => `${message}`; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/get_rules_from_config.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/get_rules_from_config.ts new file mode 100644 index 000000000000..cc97d13a030c --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/get_rules_from_config.ts @@ -0,0 +1,35 @@ +/* + * 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 path from 'path'; +import { readFileSync } from 'fs'; +import { matches } from './matches'; + +export type FileBasedConfig = Record; +export type ValueBasedConfig = Record< + string, + Record> +>; + +export const getRulesFromConfig = (configPath: string) => { + const filePath = path.resolve(__dirname, configPath); + return JSON.parse(readFileSync(filePath, 'utf-8')); +}; + +export const getRuleFromConfig = (rules: FileBasedConfig, value: string) => { + for (const key of Object.keys(rules)) { + if (matches(key, value)) { + return rules[key]; + } + } + + return undefined; +}; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/index.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/index.ts new file mode 100644 index 000000000000..ef60132e86b7 --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/index.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 * as ComplianceEngine from './compliance_engine'; +export * from './extract_regex'; +export * from './get_message'; +export * from './get_rules_from_config'; +export * from './is_color_property'; +export * from './is_valid_options'; +export * from './matches'; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/is_color_property.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/is_color_property.ts new file mode 100644 index 000000000000..ef7ad9118f81 --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/is_color_property.ts @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { Rule, Declaration } from 'postcss'; + +const COLOR_PROPERTIES = [ + 'all', + 'animation', + 'animation-name', + 'background', + 'background-color', + 'background-image', + 'border', + 'border-bottom', + 'border-bottom-color', + 'border-color', + 'border-image', + 'border-image-source', + 'border-left', + 'border-left-color', + 'border-right', + 'border-right-color', + 'border-top', + 'border-top-color', + 'box-shadow', + 'caret-color', + 'color', + 'column-rule', + 'column-rule-color', + 'content', + 'cursor', + 'filter', + 'list-style', + 'list-style-image', + 'outline', + 'outline-color', + 'text-decoration', + 'text-decoration-color', + 'text-shadow', + 'mask-image', + 'shape-outside', + 'mask-border-source', +]; + +/** + * This is intended to check a list of defined properties + * within a style and see if it's potentially modifying a property + * that can have a color. Stylelint crawls styles and will check + * each one, therefore this is to optimize the linter to + * skip any property that does not impact colors. + */ +export const isColorProperty = (prop: string) => { + return COLOR_PROPERTIES.includes(prop); +}; + +export const getColorPropertyParent = (decl: Declaration) => { + if (!isColorProperty(decl.prop)) { + return undefined; + } + + return decl.parent as Rule; +}; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/is_valid_options.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/is_valid_options.ts new file mode 100644 index 000000000000..15fae8862eaa --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/is_valid_options.ts @@ -0,0 +1,27 @@ +/* + * 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 stylelint from 'stylelint'; + +const { validateOptions } = stylelint.utils; + +export const isValidOptions = ( + postcssResult: any, + ruleName: string, + primaryOption: Record +) => { + return validateOptions(postcssResult, ruleName, { + actual: primaryOption, + possible: { + config: [(input) => typeof input === 'string'], + }, + }); +}; diff --git a/packages/osd-stylelint-plugin-stylelint/src/utils/matches.ts b/packages/osd-stylelint-plugin-stylelint/src/utils/matches.ts new file mode 100644 index 000000000000..02cc327615bd --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/src/utils/matches.ts @@ -0,0 +1,15 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { extractRegex } from './extract_regex'; + +export const matches = (matcher: string, value: string) => { + const regex = extractRegex(matcher); + if (!regex) { + return value === matcher; + } + + return regex.test(value); +}; diff --git a/packages/osd-stylelint-plugin-stylelint/tsconfig.json b/packages/osd-stylelint-plugin-stylelint/tsconfig.json new file mode 100644 index 000000000000..d7e31cada44d --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "declaration": true, + "declarationDir": "./target", + "outDir": "./target", + "stripInternal": true, + "declarationMap": true, + "types": ["jest", "node"], + "noImplicitAny": false, + }, + "include": ["./src/**/*.ts"], + "exclude": ["target"] +} diff --git a/packages/osd-stylelint-plugin-stylelint/yarn.lock b/packages/osd-stylelint-plugin-stylelint/yarn.lock new file mode 120000 index 000000000000..3f82ebc9cdba --- /dev/null +++ b/packages/osd-stylelint-plugin-stylelint/yarn.lock @@ -0,0 +1 @@ +../../yarn.lock \ No newline at end of file diff --git a/packages/osd-ui-framework/Gruntfile.js b/packages/osd-ui-framework/Gruntfile.js index 9ad26b578e08..10295493609c 100644 --- a/packages/osd-ui-framework/Gruntfile.js +++ b/packages/osd-ui-framework/Gruntfile.js @@ -28,6 +28,7 @@ * under the License. */ +const { strip } = require('comment-stripper'); const sass = require('node-sass'); const postcss = require('postcss'); const postcssConfig = require('@osd/optimizer/postcss.config.js'); @@ -74,6 +75,8 @@ module.exports = function (grunt) { Promise.all([ uiFrameworkCompile('src/kui_light.scss', 'dist/kui_light.css'), 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'), ]).then(done); }); @@ -89,7 +92,10 @@ module.exports = function (grunt) { } postcss([postcssConfig]) - .process(result.css, { from: src, to: dest }) + .process(strip(result.css.toString('utf8'), { language: 'css' }), { + from: src, + to: dest, + }) .then((result) => { grunt.file.write(dest, result.css); diff --git a/packages/osd-ui-framework/dist/kui_dark.css b/packages/osd-ui-framework/dist/kui_dark.css index aa16bcdb34d3..d559e81e46dc 100644 --- a/packages/osd-ui-framework/dist/kui_dark.css +++ b/packages/osd-ui-framework/dist/kui_dark.css @@ -1,152 +1,52 @@ -/* 1 */ -/* 1 */ -/** - * 1. Extend beta badges to at least 40% of the container's width - * 2. Fix for IE to ensure badges are visible outside of a + +
+

+ Dev tools description +

+
+ + +`; diff --git a/src/plugins/management_overview/public/components/overview_card/index.ts b/src/plugins/management_overview/public/components/overview_card/index.ts new file mode 100644 index 000000000000..d56e99bdac96 --- /dev/null +++ b/src/plugins/management_overview/public/components/overview_card/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { OverviewCard, OverviewCardProps } from './overview_card'; diff --git a/src/plugins/management_overview/public/components/overview_card/overview_card.test.tsx b/src/plugins/management_overview/public/components/overview_card/overview_card.test.tsx new file mode 100644 index 000000000000..6534fbca85f5 --- /dev/null +++ b/src/plugins/management_overview/public/components/overview_card/overview_card.test.tsx @@ -0,0 +1,27 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { render } from '@testing-library/react'; +import { OverviewCard } from './overview_card'; +import React from 'react'; + +function renderOverviewCard() { + return render( + + ); +} + +describe('OverviewCard', () => { + it('should render normally', () => { + const { container, queryByText } = renderOverviewCard(); + expect(container.firstChild).toMatchSnapshot(); + expect(queryByText('Dev Tools')).not.toBeNull(); + }); +}); diff --git a/src/plugins/management_overview/public/components/overview_card/overview_card.tsx b/src/plugins/management_overview/public/components/overview_card/overview_card.tsx new file mode 100644 index 000000000000..dad91bc1e79b --- /dev/null +++ b/src/plugins/management_overview/public/components/overview_card/overview_card.tsx @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiCard } from '@elastic/eui'; +import React from 'react'; + +export interface OverviewCardProps { + id: string; + title: string; + description: string; + onClick: () => void; +} + +export function OverviewCard(props: OverviewCardProps) { + const { id, title, description, onClick } = props; + + return ( + + ); +} diff --git a/src/plugins/management_overview/public/index.ts b/src/plugins/management_overview/public/index.ts new file mode 100644 index 000000000000..28eadd8c2f33 --- /dev/null +++ b/src/plugins/management_overview/public/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ManagementOverViewPlugin } from './plugin'; + +export { OverviewApp } from './overview_app'; +export { ManagementOverViewPluginSetup, ManagementOverViewPluginStart } from './plugin'; + +export const plugin = () => new ManagementOverViewPlugin(); diff --git a/src/plugins/management_overview/public/overview_app.ts b/src/plugins/management_overview/public/overview_app.ts new file mode 100644 index 000000000000..dfb85e8c3275 --- /dev/null +++ b/src/plugins/management_overview/public/overview_app.ts @@ -0,0 +1,14 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface OverviewApp { + /** id of plugin app */ + id: string; + /** Title of plugin displayed to the user. */ + title: string; + /** One-line description of feature displayed to the user. */ + description: string; + order: number; +} diff --git a/src/plugins/management_overview/public/plugin.ts b/src/plugins/management_overview/public/plugin.ts new file mode 100644 index 000000000000..b588d50e23da --- /dev/null +++ b/src/plugins/management_overview/public/plugin.ts @@ -0,0 +1,86 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { + AppMountParameters, + CoreSetup, + Plugin, + DEFAULT_APP_CATEGORIES, + CoreStart, +} from '../../../core/public'; +import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../home/public'; +import { MANAGEMENT_OVERVIEW_PLUGIN_ID } from '../common/constants'; +import { OverviewApp } from './overview_app'; + +interface ManagementOverviewSetupDeps { + home?: HomePublicPluginSetup; +} + +export interface ManagementOverViewPluginSetup { + register: (overviewApp: OverviewApp) => void; +} +/** @public */ +export class ManagementOverViewPlugin implements Plugin { + private readonly overviewApps = new Map(); + + private getSortedOverviewApps(): OverviewApp[] { + return [...this.overviewApps.values()].sort((a, b) => a.order - b.order); + } + + public setup( + coreSetup: CoreSetup, + { home }: ManagementOverviewSetupDeps + ): ManagementOverViewPluginSetup { + const { application, getStartServices } = coreSetup; + + if (home) { + home.featureCatalogue.register({ + id: MANAGEMENT_OVERVIEW_PLUGIN_ID, + title: i18n.translate('management.stackManagement.managementLabel', { + defaultMessage: 'Management', + }), + description: i18n.translate('management.stackManagement.managementDescription', { + defaultMessage: 'Your center location for managing the OpenSearch Stack.', + }), + icon: 'managementApp', + path: `/app/${MANAGEMENT_OVERVIEW_PLUGIN_ID}`, + showOnHomePage: false, + category: FeatureCatalogueCategory.ADMIN, + }); + } + + application.register({ + id: MANAGEMENT_OVERVIEW_PLUGIN_ID, + title: i18n.translate('management.overview.overviewTitle', { + defaultMessage: 'Overview', + }), + icon: '/plugins/home/public/assets/logos/opensearch_mark_default.svg', + order: 9000, + category: DEFAULT_APP_CATEGORIES.management, + mount: async (params: AppMountParameters) => { + const { element } = params; + const [core] = await getStartServices(); + const overviewApps = this.getSortedOverviewApps(); + + const { renderApp } = await import('./application'); + return renderApp(core, overviewApps, element); + }, + }); + + return { + register: (app: OverviewApp) => { + if (this.overviewApps.has(app.id)) { + throw new Error( + `Management overview App tool with id [${app.id}] has already been registered. Use a unique id.` + ); + } + this.overviewApps.set(app.id, app); + }, + }; + } + + public start(core: CoreStart): void {} +} diff --git a/src/plugins/maps_legacy/public/map/_custom_button.scss b/src/plugins/maps_legacy/public/map/_custom_button.scss new file mode 100644 index 000000000000..e1e9675c4748 --- /dev/null +++ b/src/plugins/maps_legacy/public/map/_custom_button.scss @@ -0,0 +1,8 @@ +.mapButton { + 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; +} diff --git a/src/plugins/maps_legacy/public/map/_leaflet_overrides.scss b/src/plugins/maps_legacy/public/map/_leaflet_overrides.scss index b75c1d7dde25..9b039be17c50 100644 --- a/src/plugins/maps_legacy/public/map/_leaflet_overrides.scss +++ b/src/plugins/maps_legacy/public/map/_leaflet_overrides.scss @@ -1,164 +1,171 @@ // SASSTODO: Create these tooltip variables in EUI // And/Or create a tooltip mixin -$temp-euiTooltipBackground: tintOrShade($euiColorFullShade, 25%, 90%); $temp-euiTooltipText: $euiColorGhost; // Converted leaflet icon sprite into background svg for custom coloring (dark mode) /* stylelint-disable-next-line max-line-length */ $visMapLeafletSprite: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 60' height='60' width='600'%3E%3Cg fill='#{hexToRGB($euiTextColor)}'%3E%3Cg%3E%3Cpath d='M18 36v6h6v-6h-6zm4 4h-2v-2h2v2z'/%3E%3Cpath d='M36 18v6h6v-6h-6zm4 4h-2v-2h2v2z'/%3E%3Cpath d='M23.142 39.145l-2.285-2.29 16-15.998 2.285 2.285z'/%3E%3C/g%3E%3Cpath d='M100 24.565l-2.096 14.83L83.07 42 76 28.773 86.463 18z'/%3E%3Cpath d='M140 20h20v20h-20z'/%3E%3Cpath d='M221 30c0 6.078-4.926 11-11 11s-11-4.922-11-11c0-6.074 4.926-11 11-11s11 4.926 11 11z'/%3E%3Cpath d='M270,19c-4.971,0-9,4.029-9,9c0,4.971,5.001,12,9,14c4.001-2,9-9.029,9-14C279,23.029,274.971,19,270,19z M270,31.5c-2.484,0-4.5-2.014-4.5-4.5c0-2.484,2.016-4.5,4.5-4.5c2.485,0,4.5,2.016,4.5,4.5C274.5,29.486,272.485,31.5,270,31.5z'/%3E%3Cg%3E%3Cpath d='M337,30.156v0.407v5.604c0,1.658-1.344,3-3,3h-10c-1.655,0-3-1.342-3-3v-10c0-1.657,1.345-3,3-3h6.345 l3.19-3.17H324c-3.313,0-6,2.687-6,6v10c0,3.313,2.687,6,6,6h10c3.314,0,6-2.687,6-6v-8.809L337,30.156'/%3E%3Cpath d='M338.72 24.637l-8.892 8.892H327V30.7l8.89-8.89z'/%3E%3Cpath d='M338.697 17.826h4v4h-4z' transform='rotate(-134.99 340.703 19.817)'/%3E%3C/g%3E%3Cg%3E%3Cpath d='M381 42h18V24h-18v18zm14-16h2v14h-2V26zm-4 0h2v14h-2V26zm-4 0h2v14h-2V26zm-4 0h2v14h-2V26z'/%3E%3Cpath d='M395 20v-4h-10v4h-6v2h22v-2h-6zm-2 0h-6v-2h6v2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A"; -.leaflet-touch .leaflet-bar, -.leaflet-draw-actions { - @include euiBottomShadowMedium($color: $euiShadowColorLarge, $opacity: 0.2); +// wrap in additional selector for enough specificity to override defaults +.visualization { + .leaflet-touch .leaflet-bar, + .leaflet-draw-actions { + @include euiBottomShadowMedium($color: $euiShadowColorLarge, $opacity: 0.2); - border: none; -} - -.leaflet-container { - background: $euiColorEmptyShade; - - // the heatmap layer plugin logs an error to the console when the map is in a 0-sized container - min-width: 1px !important; - min-height: 1px !important; -} - -.leaflet-clickable { - &:hover { - stroke-width: $euiSizeS; - stroke-opacity: 0.8; + border: none; } -} -/** - * 1. Since Leaflet is an external library, we also have to provide EUI variables - * to non-override colors for darkmode. - */ + .leaflet-container { + background: $euiColorEmptyShade; + font-family: var(--font-text); -.leaflet-draw-actions, -.leaflet-control { - a { - background-color: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightShade); /* 1 */ - border-color: lightOrDarkTheme($euiColorLightShade, $euiColorMediumShade) !important; /* 1 */ - color: $euiTextColor !important; /* 1 */ + // the heatmap layer plugin logs an error to the console when the map is in a 0-sized container + min-width: 1px !important; + min-height: 1px !important; + } + .leaflet-clickable { &:hover { - background-color: $euiColorLightestShade; + stroke-width: $euiSizeS; + stroke-opacity: 0.8; } } -} -.leaflet-touch .leaflet-bar a:first-child { - border-top-left-radius: $euiBorderRadius; - border-top-right-radius: $euiBorderRadius; -} + /** + * 1. Since Leaflet is an external library, we also have to provide EUI variables + * to non-override colors for darkmode. + */ + + .leaflet-draw-actions, + .leaflet-control { + a { + background-color: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightShade); /* 1 */ + border-color: lightOrDarkTheme($euiColorLightShade, $euiColorMediumShade) !important; /* 1 */ + color: $euiTextColor !important; /* 1 */ + + &:hover { + background-color: $euiColorLightestShade; + } + } + } -.leaflet-touch .leaflet-bar a:last-child { - border-bottom-left-radius: $euiBorderRadius; - border-bottom-right-radius: $euiBorderRadius; -} + .leaflet-draw-actions a { + font-family: var(--font-text); + } -.leaflet-retina .leaflet-draw-toolbar a { - background-image: url($visMapLeafletSprite); /* 1 */ -} + .leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: $euiBorderRadius; + border-top-right-radius: $euiBorderRadius; + } -.leaflet-control-layers-expanded { - padding: 0; - margin: 0; + .leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: $euiBorderRadius; + border-bottom-right-radius: $euiBorderRadius; + } + + .leaflet-retina .leaflet-draw-toolbar a { + background-image: url($visMapLeafletSprite); /* 1 */ + } - @include fontSize(11px); + .leaflet-control-layers-expanded { + padding: 0; + margin: 0; - font-family: $euiFontFamily; - font-weight: $euiFontWeightMedium; - line-height: $euiLineHeight; + @include fontSize(11px); - label { + font-family: var(--font-text); font-weight: $euiFontWeightMedium; + line-height: $euiLineHeight; + + label { + font-weight: $euiFontWeightMedium; + margin: 0; + padding: 0; + } + } + + /* over-rides leaflet popup styles to look like OpenSearch Dashboards tooltip */ + .leaflet-popup-content-wrapper { margin: 0; padding: 0; + background: $euiTooltipBackgroundColor; + color: $temp-euiTooltipText; + border-radius: $euiBorderRadius !important; // Override all positions the popup might be at } -} - -/* over-rides leaflet popup styles to look like OpenSearch Dashboards tooltip */ -.leaflet-popup-content-wrapper { - margin: 0; - padding: 0; - background: $temp-euiTooltipBackground; - color: $temp-euiTooltipText; - border-radius: $euiBorderRadius !important; // Override all positions the popup might be at -} -.leaflet-popup { - pointer-events: none; -} + .leaflet-popup { + pointer-events: none; + } -.leaflet-popup-content { - margin: 0; + .leaflet-popup-content { + margin: 0; - @include euiFontSizeS; + @include euiFontSizeS; - font-weight: $euiFontWeightRegular; - word-wrap: break-word; - overflow: hidden; - pointer-events: none; + font-weight: $euiFontWeightRegular; + word-wrap: break-word; + overflow: hidden; + pointer-events: none; - > * { - margin: $euiSizeS $euiSizeS 0; - } + > * { + margin: $euiSizeS $euiSizeS 0; + } - > :last-child { - margin-bottom: $euiSizeS; - } + > :last-child { + margin-bottom: $euiSizeS; + } - table { - td, - th { - padding: $euiSizeXS; + table { + td, + th { + padding: $euiSizeXS; + } } } -} -.leaflet-popup-tip-container, -.leaflet-popup-close-button, -.leaflet-draw-tooltip { - display: none !important; -} + .leaflet-popup-tip-container, + .leaflet-popup-close-button, + .leaflet-draw-tooltip { + display: none !important; + } -.leaflet-container .leaflet-control-attribution { - background-color: transparentize($euiColorEmptyShade, 0.7); - color: $euiColorDarkShade; + .leaflet-container .leaflet-control-attribution { + background-color: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightShade); + color: $euiColorDarkShade; - // attributions are appended in blocks of

tags, this will allow them to display in one line - p { - display: inline; + // attributions are appended in blocks of

tags, this will allow them to display in one line + p { + display: inline; + } } -} -.leaflet-touch .leaflet-control-zoom-in, -.leaflet-touch .leaflet-control-zoom-out { - text-indent: -10000px; - background-repeat: no-repeat; - background-position: center; -} + .leaflet-touch .leaflet-control-zoom-in, + .leaflet-touch .leaflet-control-zoom-out { + text-indent: -10000px; + background-repeat: no-repeat; + background-position: center; + } -// Custom SVG as background for zoom controls based off of EUI glyphs plusInCircleFilled and minusInCircleFilled -.leaflet-touch .leaflet-control-zoom-in { - background-image: url("data:image/svg+xml,%0A%3Csvg width='15px' height='15px' viewBox='0 0 15 15' version='1.1' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='#{hexToRGB($euiTextColor)}' d='M8,7 L8,3.5 C8,3.22385763 7.77614237,3 7.5,3 C7.22385763,3 7,3.22385763 7,3.5 L7,7 L3.5,7 C3.22385763,7 3,7.22385763 3,7.5 C3,7.77614237 3.22385763,8 3.5,8 L7,8 L7,11.5 C7,11.7761424 7.22385763,12 7.5,12 C7.77614237,12 8,11.7761424 8,11.5 L8,8 L11.5,8 C11.7761424,8 12,7.77614237 12,7.5 C12,7.22385763 11.7761424,7 11.5,7 L8,7 Z M7.5,15 C3.35786438,15 0,11.6421356 0,7.5 C0,3.35786438 3.35786438,0 7.5,0 C11.6421356,0 15,3.35786438 15,7.5 C15,11.6421356 11.6421356,15 7.5,15 Z' /%3E%3C/svg%3E"); -} + // Custom SVG as background for zoom controls based off of EUI glyphs plusInCircleFilled and minusInCircleFilled + .leaflet-touch .leaflet-control-zoom-in { + background-image: url("data:image/svg+xml,%0A%3Csvg width='15px' height='15px' viewBox='0 0 15 15' version='1.1' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='#{hexToRGB($euiTextColor)}' d='M8,7 L8,3.5 C8,3.22385763 7.77614237,3 7.5,3 C7.22385763,3 7,3.22385763 7,3.5 L7,7 L3.5,7 C3.22385763,7 3,7.22385763 3,7.5 C3,7.77614237 3.22385763,8 3.5,8 L7,8 L7,11.5 C7,11.7761424 7.22385763,12 7.5,12 C7.77614237,12 8,11.7761424 8,11.5 L8,8 L11.5,8 C11.7761424,8 12,7.77614237 12,7.5 C12,7.22385763 11.7761424,7 11.5,7 L8,7 Z M7.5,15 C3.35786438,15 0,11.6421356 0,7.5 C0,3.35786438 3.35786438,0 7.5,0 C11.6421356,0 15,3.35786438 15,7.5 C15,11.6421356 11.6421356,15 7.5,15 Z' /%3E%3C/svg%3E"); + } -.leaflet-touch .leaflet-control-zoom-out { - background-image: url("data:image/svg+xml,%0A%3Csvg width='15px' height='15px' viewBox='0 0 15 15' version='1.1' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='#{hexToRGB($euiTextColor)}' d='M7.5,0 C11.6355882,0 15,3.36441176 15,7.5 C15,11.6355882 11.6355882,15 7.5,15 C3.36441176,15 0,11.6355882 0,7.5 C0,3.36441176 3.36441176,0 7.5,0 Z M3.5,7 C3.22385763,7 3,7.22385763 3,7.5 C3,7.77614237 3.22385763,8 3.5,8 L11.5,8 C11.7761424,8 12,7.77614237 12,7.5 C12,7.22385763 11.7761424,7 11.5,7 L3.5,7 Z' /%3E%3C/svg%3E"); -} + .leaflet-touch .leaflet-control-zoom-out { + background-image: url("data:image/svg+xml,%0A%3Csvg width='15px' height='15px' viewBox='0 0 15 15' version='1.1' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='#{hexToRGB($euiTextColor)}' d='M7.5,0 C11.6355882,0 15,3.36441176 15,7.5 C15,11.6355882 11.6355882,15 7.5,15 C3.36441176,15 0,11.6355882 0,7.5 C0,3.36441176 3.36441176,0 7.5,0 Z M3.5,7 C3.22385763,7 3,7.22385763 3,7.5 C3,7.77614237 3.22385763,8 3.5,8 L11.5,8 C11.7761424,8 12,7.77614237 12,7.5 C12,7.22385763 11.7761424,7 11.5,7 L3.5,7 Z' /%3E%3C/svg%3E"); + } -// Filter to desaturate mapquest tiles + // Filter to desaturate mapquest tiles -img.leaflet-tile { - @if lightness($euiTextColor) < 50 { - filter: brightness(1.03) grayscale(0.73); - } @else { - filter: invert(1) brightness(1.75) grayscale(1); + img.leaflet-tile { + @if lightness($euiTextColor) < 50 { + filter: brightness(1.03) grayscale(0.73); + } @else { + filter: invert(1) brightness(1.75) grayscale(1); + } } -} -img.leaflet-tile.filters-off { - filter: none; + img.leaflet-tile.filters-off { + filter: lightOrDarkTheme(none, null); + } } diff --git a/src/plugins/maps_legacy/public/map/_legend.scss b/src/plugins/maps_legacy/public/map/_legend.scss index 43ecb5ac8127..32fc07f7960c 100644 --- a/src/plugins/maps_legacy/public/map/_legend.scss +++ b/src/plugins/maps_legacy/public/map/_legend.scss @@ -2,7 +2,7 @@ @include fontSize(11px); @include euiBottomShadowMedium($color: $euiShadowColorLarge, $opacity: 0.1); - font-family: $euiFontFamily; + font-family: var(--font-text); font-weight: $euiFontWeightMedium; line-height: $euiLineHeight; color: $euiColorDarkShade; diff --git a/src/plugins/maps_legacy/public/map/index.scss b/src/plugins/maps_legacy/public/map/index.scss index f2a91bbac621..920852612c95 100644 --- a/src/plugins/maps_legacy/public/map/index.scss +++ b/src/plugins/maps_legacy/public/map/index.scss @@ -1,2 +1,3 @@ +@import "./custom_button"; @import "./leaflet_overrides"; @import "./legend"; diff --git a/src/plugins/maps_legacy/public/map/opensearch_dashboards_map.js b/src/plugins/maps_legacy/public/map/opensearch_dashboards_map.js index 3ca067c27796..804795f5a89b 100644 --- a/src/plugins/maps_legacy/public/map/opensearch_dashboards_map.js +++ b/src/plugins/maps_legacy/public/map/opensearch_dashboards_map.js @@ -41,6 +41,7 @@ import { i18n } from '@osd/i18n'; import { ORIGIN } from '../common/constants/origin'; import { getToasts } from '../opensearch_dashboards_services'; import { L } from '../leaflet'; +import { euiThemeVars } from '@osd/ui-shared-deps/theme'; function makeFitControl(fitContainer, opensearchDashboardsMap) { // eslint-disable-next-line no-undef @@ -61,7 +62,7 @@ function makeFitControl(fitContainer, opensearchDashboardsMap) { ); $(this._fitContainer) .html( - `` + `` ) .on('click', (e) => { e.preventDefault(); @@ -242,7 +243,7 @@ export class OpenSearchDashboardsMap extends EventEmitter { addLayer(opensearchDashboardsLayer) { const onshowTooltip = (event) => { - if (!this._showTooltip) { + if (!this._showTooltip || !event.content) { return; } @@ -474,7 +475,7 @@ export class OpenSearchDashboardsMap extends EventEmitter { } addDrawControl() { - const drawColor = '#000'; + const drawColor = euiThemeVars.euiColorInk; const drawOptions = { draw: { polyline: false, diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx index d4dbd4c9f5ef..5fa97eb0a7d2 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx @@ -43,7 +43,6 @@ const dataShim = { }; describe('TopNavMenu', () => { - const WRAPPER_SELECTOR = '.osdTopNavMenu__wrapper'; const TOP_NAV_ITEM_SELECTOR = 'TopNavMenuItem'; const SEARCH_BAR_SELECTOR = 'SearchBar'; const menuItems: TopNavMenuData[] = [ @@ -66,28 +65,24 @@ describe('TopNavMenu', () => { it('Should render nothing when no config is provided', () => { const component = shallowWithIntl(); - expect(component.find(WRAPPER_SELECTOR).length).toBe(0); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(0); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(0); }); it('Should not render menu items when config is empty', () => { const component = shallowWithIntl(); - expect(component.find(WRAPPER_SELECTOR).length).toBe(0); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(0); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(0); }); it('Should render 1 menu item', () => { const component = shallowWithIntl(); - expect(component.find(WRAPPER_SELECTOR).length).toBe(1); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(1); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(0); }); it('Should render multiple menu items', () => { const component = shallowWithIntl(); - expect(component.find(WRAPPER_SELECTOR).length).toBe(1); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(menuItems.length); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(0); }); @@ -96,7 +91,6 @@ describe('TopNavMenu', () => { const component = shallowWithIntl( ); - expect(component.find(WRAPPER_SELECTOR).length).toBe(1); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(0); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(1); }); @@ -105,7 +99,6 @@ describe('TopNavMenu', () => { const component = shallowWithIntl( ); - expect(component.find(WRAPPER_SELECTOR).length).toBe(1); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(menuItems.length); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(1); }); @@ -170,7 +163,6 @@ describe('TopNavMenu', () => { await refresh(); - expect(component.find(WRAPPER_SELECTOR).length).toBe(1); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(1); // menu is rendered outside of the component 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 bddea070fd12..15b6c6bff057 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 @@ -115,22 +115,21 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { function renderLayout() { const { setMenuMountPoint } = props; const menuClassName = classNames('osdTopNavMenu', props.className); - const wrapperClassName = 'osdTopNavMenu__wrapper'; if (setMenuMountPoint) { return ( <> - {renderMenu(menuClassName)} + {renderMenu(menuClassName)} - {renderSearchBar()} + {renderSearchBar()} ); } else { return ( - + <> {renderMenu(menuClassName)} {renderSearchBar()} - + ); } } diff --git a/src/plugins/opensearch_dashboards_overview/public/components/overview/__snapshots__/overview.test.tsx.snap b/src/plugins/opensearch_dashboards_overview/public/components/overview/__snapshots__/overview.test.tsx.snap index 198e0119ebd8..e352dd58236c 100644 --- a/src/plugins/opensearch_dashboards_overview/public/components/overview/__snapshots__/overview.test.tsx.snap +++ b/src/plugins/opensearch_dashboards_overview/public/components/overview/__snapshots__/overview.test.tsx.snap @@ -182,7 +182,7 @@ exports[`Overview render 1`] = ` id="osdOverviewMore__title" > @@ -611,7 +611,7 @@ exports[`Overview without features 1`] = ` id="osdOverviewMore__title" > diff --git a/src/plugins/opensearch_dashboards_overview/public/components/overview/overview.tsx b/src/plugins/opensearch_dashboards_overview/public/components/overview/overview.tsx index 8287f3edb397..3df491b1b422 100644 --- a/src/plugins/opensearch_dashboards_overview/public/components/overview/overview.tsx +++ b/src/plugins/opensearch_dashboards_overview/public/components/overview/overview.tsx @@ -222,7 +222,7 @@ export const Overview: FC = ({ newsFetchResult, solutions, features, bran

diff --git a/src/plugins/opensearch_dashboards_usage_collection/server/collectors/management/schema.ts b/src/plugins/opensearch_dashboards_usage_collection/server/collectors/management/schema.ts index 72d8aa4d78e7..5be224b85204 100644 --- a/src/plugins/opensearch_dashboards_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/opensearch_dashboards_usage_collection/server/collectors/management/schema.ts @@ -40,6 +40,8 @@ export const stackManagementSchema: MakeSchemaFrom = { 'visualization:regionmap:showWarnings': { type: 'boolean' }, 'visualization:dimmingOpacity': { type: 'float' }, 'visualization:tileMap:maxPrecision': { type: 'long' }, + 'visualization:enablePluginAugmentation': { type: 'boolean' }, + 'visualization:enablePluginAugmentation.maxPluginObjects': { type: 'number' }, 'securitySolution:ipReputationLinks': { type: 'text' }, 'csv:separator': { type: 'keyword' }, 'visualization:tileMap:WMSdefaults': { type: 'text' }, diff --git a/src/plugins/region_map/public/choropleth_layer.js b/src/plugins/region_map/public/choropleth_layer.js index 10d2389c5761..84329953c9f0 100644 --- a/src/plugins/region_map/public/choropleth_layer.js +++ b/src/plugins/region_map/public/choropleth_layer.js @@ -32,6 +32,7 @@ import $ from 'jquery'; import _ from 'lodash'; import d3 from 'd3'; import { i18n } from '@osd/i18n'; +import { euiThemeVars } from '@osd/ui-shared-deps/theme'; import * as topojson from 'topojson-client'; import { getNotifications } from './opensearch_dashboards_services'; import { colorUtil, OpenSearchDashboardsMapLayer } from '../../maps_legacy/public'; @@ -46,7 +47,7 @@ import { const EMPTY_STYLE = { weight: 1, opacity: 0.6, - color: 'rgb(200,200,200)', + color: euiThemeVars.euiColorMediumShade, fillOpacity: 0, }; diff --git a/src/plugins/saved_objects/README.md b/src/plugins/saved_objects/README.md index 3b6dc4f7a79c..2f7d98dbb36b 100644 --- a/src/plugins/saved_objects/README.md +++ b/src/plugins/saved_objects/README.md @@ -2,77 +2,78 @@ The saved object plugin provides all the core services and functionalities of saved objects. It is utilized by many core plugins such as [`visualization`](../visualizations/), [`dashboard`](../dashboard/) and [`visBuilder`](../vis_builder/), as well as external plugins. Saved object is the primary way to store app and plugin data in a standardized form in OpenSearch Dashboards. They allow plugin developers to manage creating, saving, editing and retrieving data for the application. They can also make reference to other saved objects and have useful features out of the box, such as migrations and strict typings. The saved objects can be managed by the Saved Object Management UI. -## Save relationships to index pattern +### Relationships -Saved objects that have relationships to index patterns are saved using the [`kibanaSavedObjectMeta`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L59) attribute and the [`references`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L60) array structure. Functions from the data plugin are used by the saved object plugin to manage this index pattern relationship. +Saved objects can persist parent/child relationships to other saved objects via `references`. These relationships can be viewed on the UI in the [saved objects management plugin](src/core/server/saved_objects_management/README.md). Relationships can be useful to combine existing saved objects to produce new ones, such as using an index pattern as the source for a visualization, or a dashboard consisting of many visualizations. -A standard saved object and its index pattern relationship: +Some saved object fields have pre-defined logic. For example, if a saved object type has a `searchSource` field indicating an index pattern relationship, a reference will automatically be created using the [`kibanaSavedObjectMeta`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L59) attribute and the [`references`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts#L60) array structure. Functions from the data plugin are used by the saved object plugin to manage this index pattern relationship. + +An example of a visualization saved object and its index pattern relationship: ```ts "kibanaSavedObjectMeta" : { "searchSourceJSON" : """{"filter":[],"query":{"query":"","language":"kuery"},"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}""" - } - }, - "type" : "visualization", - "references" : [ - { - "name" : "kibanaSavedObjectMeta.searchSourceJSON.index", - "type" : "index-pattern", - "id" : "90943e30-9a47-11e8-b64d-95841ca0b247" - } - ], +} +"type" : "visualization", +"references" : [ + { + "name" : "kibanaSavedObjectMeta.searchSourceJSON.index", + "type" : "index-pattern", + "id" : "90943e30-9a47-11e8-b64d-95841ca0b247" + } +], ``` ### Saving a saved object -When saving a saved object and its relationship to the index pattern: +When saving a saved object and its relationship to the index pattern: 1. A saved object will be built using [`buildSavedObject`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts#L46) function. Services such as hydrating index pattern, initializing and serializing the saved object are set, and configs such as saved object id, migration version are defined. -2. The saved object will then be serialized by three steps: - - a. By using [`extractReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/extract_references.ts#L35) function from the data plugin, the index pattern information will be extracted using the index pattern id within the `kibanaSavedObjectMeta`, and the id will be replaced by a reference name, such as `indexRefName`. A corresponding index pattern object will then be created to include more detailed information of the index pattern: name (`kibanaSavedObjectMeta.searchSourceJSON.index`), type, and id. - - ```ts - let searchSourceFields = { ...state }; - const references = []; - - if (searchSourceFields.index) { - const indexId = searchSourceFields.index.id || searchSourceFields.index; - const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; - references.push({ - name: refName, - type: 'index-pattern', - id: indexId - }); - searchSourceFields = { ...searchSourceFields, - indexRefName: refName, - index: undefined - }; - } - ``` +2. The saved object will then be serialized by three steps: - b. The `indexRefName` along with other information will be stringified and saved into `kibanaSavedObjectMeta.searchSourceJSON`. - - c. Saved object client will create the reference array attribute, and the index pattern object will be pushed into the reference array. + a. By using [`extractReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/extract_references.ts#L35) function from the data plugin, the index pattern information will be extracted using the index pattern id within the `kibanaSavedObjectMeta`, and the id will be replaced by a reference name, such as `indexRefName`. A corresponding index pattern object will then be created to include more detailed information of the index pattern: name (`kibanaSavedObjectMeta.searchSourceJSON.index`), type, and id. + ```ts + let searchSourceFields = { ...state }; + const references = []; + + if (searchSourceFields.index) { + const indexId = searchSourceFields.index.id || searchSourceFields.index; + const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; + references.push({ + name: refName, + type: 'index-pattern', + id: indexId, + }); + searchSourceFields = { ...searchSourceFields, indexRefName: refName, index: undefined }; + } + ``` + + b. The `indexRefName` along with other information will be stringified and saved into `kibanaSavedObjectMeta.searchSourceJSON`. + + c. Saved object client will create the reference array attribute, and the index pattern object will be pushed into the reference array. ### Loading an existing or creating a new saved object -1. When loading an existing object or creating a new saved object, [`initializeSavedObject`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/initialize_saved_object.ts#L38) function will be called. +1. When loading an existing object or creating a new saved object, [`initializeSavedObject`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/initialize_saved_object.ts#L38) function will be called. 2. The saved object will be deserialized in the [`applyOpenSearchResp`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/saved_objects/public/saved_object/helpers/apply_opensearch_resp.ts#L50) function. - a. Using [`injectReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/inject_references.ts#L34) function from the data plugin, the index pattern reference name within the `kibanaSavedObject` will be substituted by the index pattern id and the corresponding index pattern reference object will be deleted if filters are applied. + a. Using [`injectReferences`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/data/common/search/search_source/inject_references.ts#L34) function from the data plugin, the index pattern reference name within the `kibanaSavedObject` will be substituted by the index pattern id and the corresponding index pattern reference object will be deleted if filters are applied. + + ```ts + searchSourceReturnFields.index = reference.id; + delete searchSourceReturnFields.indexRefName; + ``` - ```ts - searchSourceReturnFields.index = reference.id; - delete searchSourceReturnFields.indexRefName; - ``` +### Creating a new saved object type -### Others - -If a saved object type wishes to have additional custom functionalities when extracting/injecting references, or after OpenSearch's response, it can define functions in the class constructor when extending the `SavedObjectClass`. For example, visualization plugin's [`SavedVis`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#L91) class has additional `extractReferences`, `injectReferences` and `afterOpenSearchResp` functions defined in [`_saved_vis.ts`](../visualizations/public/saved_visualizations/_saved_vis.ts). +Steps need to be done on both the public/client-side & the server-side for creating a new saved object type. + +Client-side: + +1. Define a class that extends `SavedObjectClass`. This is where custom functionalities, such as extracting/injecting references, or overriding `afterOpenSearchResp` can be set in the constructor. For example, visualization plugin's [`SavedVis`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/4a06f5a6fe404a65b11775d292afaff4b8677c33/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts#L91) class has additional `extractReferences`, `injectReferences` and `afterOpenSearchResp` functions defined in [`_saved_vis.ts`](../visualizations/public/saved_visualizations/_saved_vis.ts), and set in the `SavedVis` constructor. ```ts class SavedVis extends SavedObjectClass { @@ -85,14 +86,71 @@ class SavedVis extends SavedObjectClass { afterOpenSearchResp: async (savedObject: SavedObject) => { const savedVis = (savedObject as any) as ISavedVis; ... ... - + return (savedVis as any) as SavedObject; }, ``` +2. Optionally create a loader class that extends `SavedObjectLoader`. This can be useful for performing default CRUD operations on this particular saved object type, as well as overriding default utility functions like `find`. For example, the `visualization` saved object overrides `mapHitSource` (used in `find` & `findAll`) to do additional checking on the returned source object, such as if the returned type is valid: + +```ts +class SavedObjectLoaderVisualize extends SavedObjectLoader { + mapHitSource = (source: Record, id: string) => { + const visTypes = visualizationTypes; + ... ... + let typeName = source.typeName; + if (source.visState) { + try { + typeName = JSON.parse(String(source.visState)).type; + } catch (e) { + /* missing typename handled below */ + } + } + + if (!typeName || !visTypes.get(typeName)) { + source.error = 'Unknown visualization type'; + return source; + } + ... ... + return source; + }; +``` + +The loader can then be instantiated once and referenced when needed. For example, the `visualizations` plugin creates and sets it in its `services` in the plugin's start lifecycle: + +```ts +public start( + core: CoreStart, + { data, expressions, uiActions, embeddable, dashboard }: VisualizationsStartDeps +): VisualizationsStart { + ... ... + const savedVisualizationsLoader = createSavedVisLoader({ + savedObjectsClient: core.savedObjects.client, + indexPatterns: data.indexPatterns, + search: data.search, + chrome: core.chrome, + overlays: core.overlays, + visualizationTypes: types, + }); + setSavedVisualizationsLoader(savedVisualizationsLoader); + ... ... +} +``` + +Server-side: + +1. Define the new type that is of type `SavedObjectsType`, which is where various settings can be configured, including the index mappings when the object is stored in the system index. To see an example type definition, you can refer to the [visualization saved object type](src/plugins/visualizations/server/saved_objects/visualization.ts). +2. Register the new type in the respective plugin's setup lifecycle function. For example, the `visualizations` plugin registers the `visualization` saved object type like below: + +```ts +core.savedObjects.registerType(visualizationSavedObjectType); +``` + +To make the new type manageable in the `saved_objects_management` plugin, refer to the [plugin README](src/plugins/saved_objects_management/README.md) + ## Migration -When a saved object is created using a previous version, the migration will trigger if there is a new way of saving the saved object and the migration functions alter the structure of the old saved object to follow the new structure. Migrations can be defined in the specific saved object type in the plugin's server folder. For example, +When a saved object is created using a previous version, the migration will trigger if there is a new way of saving the saved object and the migration functions alter the structure of the old saved object to follow the new structure. Migrations can be defined in the specific saved object type in the plugin's server folder. For example, ```ts export const visualizationSavedObjectType: SavedObjectsType = { @@ -116,4 +174,4 @@ The migraton version will be saved as a `migrationVersion` attribute in the save }, ``` -For a more detailed explanation on the migration, refer to [`saved objects management`](src/core/server/saved_objects/migrations/README.md). \ No newline at end of file +For a more detailed explanation on the migration, refer to [`saved objects management`](src/core/server/saved_objects/migrations/README.md). diff --git a/src/plugins/saved_objects/common/index.ts b/src/plugins/saved_objects/common/index.ts index 2d63a566b477..248fd2f508f0 100644 --- a/src/plugins/saved_objects/common/index.ts +++ b/src/plugins/saved_objects/common/index.ts @@ -29,4 +29,7 @@ */ export const PER_PAGE_SETTING = 'savedObjects:perPage'; +export const PER_PAGE_VALUE = 20; + export const LISTING_LIMIT_SETTING = 'savedObjects:listingLimit'; +export const LISTING_LIMIT_VALUE = 1000; diff --git a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts index 7e10a68c2d1f..3b1eea303f23 100644 --- a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts +++ b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts @@ -28,7 +28,6 @@ * under the License. */ -import Bluebird from 'bluebird'; import { createSavedObjectClass } from './saved_object'; import { SavedObject, @@ -76,16 +75,16 @@ describe('Saved Object', () => { */ function stubOpenSearchResponse(mockDocResponse: SimpleSavedObject) { // Stub out search for duplicate title: - savedObjectsClientStub.get = jest.fn().mockReturnValue(Bluebird.resolve(mockDocResponse)); - savedObjectsClientStub.update = jest.fn().mockReturnValue(Bluebird.resolve(mockDocResponse)); + savedObjectsClientStub.get = jest.fn().mockReturnValue(Promise.resolve(mockDocResponse)); + savedObjectsClientStub.update = jest.fn().mockReturnValue(Promise.resolve(mockDocResponse)); savedObjectsClientStub.find = jest .fn() - .mockReturnValue(Bluebird.resolve({ savedObjects: [], total: 0 })); + .mockReturnValue(Promise.resolve({ savedObjects: [], total: 0 })); savedObjectsClientStub.bulkGet = jest .fn() - .mockReturnValue(Bluebird.resolve({ savedObjects: [mockDocResponse] })); + .mockReturnValue(Promise.resolve({ savedObjects: [mockDocResponse] })); } function stubSavedObjectsClientCreate( @@ -94,7 +93,7 @@ describe('Saved Object', () => { ) { savedObjectsClientStub.create = jest .fn() - .mockReturnValue(resolve ? Bluebird.resolve(resp) : Bluebird.reject(resp)); + .mockReturnValue(resolve ? Promise.resolve(resp) : Promise.reject(resp)); } /** @@ -193,7 +192,7 @@ describe('Saved Object', () => { return createInitializedSavedObject({ type: 'dashboard', id: myId }).then((savedObject) => { savedObjectsClientStub.create = jest.fn().mockImplementation(() => { expect(savedObject.id).toBe(myId); - return Bluebird.resolve({ id: myId }); + return Promise.resolve({ id: myId }); }); savedObject.copyOnSave = false; @@ -227,7 +226,7 @@ describe('Saved Object', () => { return createInitializedSavedObject({ type: 'dashboard', id }).then((savedObject) => { savedObjectsClientStub.create = jest.fn().mockImplementation(() => { expect(savedObject.isSaving).toBe(true); - return Bluebird.resolve({ + return Promise.resolve({ type: 'dashboard', id, _version: 'foo', @@ -246,7 +245,7 @@ describe('Saved Object', () => { return createInitializedSavedObject({ type: 'dashboard' }).then((savedObject) => { savedObjectsClientStub.create = jest.fn().mockImplementation(() => { expect(savedObject.isSaving).toBe(true); - return Bluebird.reject(''); + return Promise.reject(); }); expect(savedObject.isSaving).toBe(false); @@ -681,7 +680,7 @@ describe('Saved Object', () => { ); indexPattern.title = indexPattern.id!; savedObject.searchSource!.setField('index', indexPattern); - return Bluebird.resolve(indexPattern); + return Promise.resolve(indexPattern); }); expect(!!savedObject.searchSource!.getField('index')).toBe(false); diff --git a/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts b/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts index fa329d9032b8..6c31ed0320fa 100644 --- a/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts +++ b/src/plugins/saved_objects/public/saved_object/saved_object_loader.ts @@ -126,18 +126,27 @@ export class SavedObjectLoader { * @param search * @param size * @param fields + * @param hasReference Optional field to specify a reference + * @param searchFields Optional field to specify the search fields in the query * @returns {Promise} */ - findAll(search: string = '', size: number = 100, fields?: string[]) { + findAll( + search: string = '', + size: number = 100, + fields?: string[], + hasReference?: SavedObjectsFindOptions['hasReference'], + searchFields: string[] = ['title^3', 'description'] + ) { return this.savedObjectsClient .find>({ type: this.lowercaseType, search: search ? `${search}*` : undefined, perPage: size, page: 1, - searchFields: ['title^3', 'description'], + searchFields, defaultSearchOperator: 'AND', fields, + hasReference, } as SavedObjectsFindOptions) .then((resp) => { return { diff --git a/src/plugins/saved_objects/server/ui_settings.ts b/src/plugins/saved_objects/server/ui_settings.ts index bba4a7e61d89..32f2bda01bae 100644 --- a/src/plugins/saved_objects/server/ui_settings.ts +++ b/src/plugins/saved_objects/server/ui_settings.ts @@ -32,14 +32,19 @@ import { i18n } from '@osd/i18n'; import { schema } from '@osd/config-schema'; import { UiSettingsParams } from 'opensearch-dashboards/server'; -import { PER_PAGE_SETTING, LISTING_LIMIT_SETTING } from '../common'; +import { + PER_PAGE_SETTING, + PER_PAGE_VALUE, + LISTING_LIMIT_SETTING, + LISTING_LIMIT_VALUE, +} from '../common'; export const uiSettings: Record = { [PER_PAGE_SETTING]: { name: i18n.translate('savedObjects.advancedSettings.perPageTitle', { defaultMessage: 'Objects per page', }), - value: 20, + value: PER_PAGE_VALUE, type: 'number', description: i18n.translate('savedObjects.advancedSettings.perPageText', { defaultMessage: 'Number of objects to show per page in the load dialog', @@ -51,7 +56,7 @@ export const uiSettings: Record = { defaultMessage: 'Objects listing limit', }), type: 'number', - value: 1000, + value: LISTING_LIMIT_VALUE, description: i18n.translate('savedObjects.advancedSettings.listingLimitText', { defaultMessage: 'Number of objects to fetch for the listing pages', }), diff --git a/src/plugins/saved_objects_management/opensearch_dashboards.json b/src/plugins/saved_objects_management/opensearch_dashboards.json index 6d02893311e3..f76b69999ecb 100644 --- a/src/plugins/saved_objects_management/opensearch_dashboards.json +++ b/src/plugins/saved_objects_management/opensearch_dashboards.json @@ -3,8 +3,15 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["management", "data"], - "optionalPlugins": ["dashboard", "visualizations", "discover", "home", "visBuilder"], + "requiredPlugins": ["management", "data", "uiActions"], + "optionalPlugins": [ + "dashboard", + "visualizations", + "discover", + "home", + "visBuilder", + "visAugmenter" + ], "extraPublicDirs": ["public/lib"], "requiredBundles": ["opensearchDashboardsReact", "home"] } diff --git a/src/plugins/saved_objects_management/public/index.ts b/src/plugins/saved_objects_management/public/index.ts index 2377afe175c4..317b3079efa0 100644 --- a/src/plugins/saved_objects_management/public/index.ts +++ b/src/plugins/saved_objects_management/public/index.ts @@ -48,6 +48,8 @@ export { } from './services'; export { ProcessedImportResponse, processImportResponse, FailedImport } from './lib'; export { SavedObjectRelation, SavedObjectWithMetadata, SavedObjectMetadata } from './types'; +export { SAVED_OBJECT_DELETE_TRIGGER, savedObjectDeleteTrigger } from './triggers'; +export { SavedObjectDeleteContext } from './ui_actions_bootstrap'; export function plugin(initializerContext: PluginInitializerContext) { return new SavedObjectsManagementPlugin(); diff --git a/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts index ab524bb5d993..f537bac45522 100644 --- a/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts +++ b/src/plugins/saved_objects_management/public/lib/in_app_url.test.ts @@ -77,6 +77,22 @@ describe('canViewInApp', () => { expect(canViewInApp(uiCapabilities, 'visualizations')).toEqual(false); }); + it('should handle augment-vis', () => { + let uiCapabilities = createCapabilities({ + visAugmenter: { + show: true, + }, + }); + expect(canViewInApp(uiCapabilities, 'augment-vis')).toEqual(true); + + uiCapabilities = createCapabilities({ + visAugmenter: { + show: false, + }, + }); + expect(canViewInApp(uiCapabilities, 'augment-vis')).toEqual(false); + }); + it('should handle index patterns', () => { let uiCapabilities = createCapabilities({ management: { diff --git a/src/plugins/saved_objects_management/public/lib/in_app_url.ts b/src/plugins/saved_objects_management/public/lib/in_app_url.ts index e55eaa858f4a..ea8a373bca8b 100644 --- a/src/plugins/saved_objects_management/public/lib/in_app_url.ts +++ b/src/plugins/saved_objects_management/public/lib/in_app_url.ts @@ -38,6 +38,8 @@ export function canViewInApp(uiCapabilities: Capabilities, type: string): boolea case 'visualization': case 'visualizations': return uiCapabilities.visualize.show as boolean; + case 'augment-vis': + return uiCapabilities.visAugmenter.show as boolean; case 'index-pattern': case 'index-patterns': case 'indexPatterns': 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 2c42df5c7824..a1c7b5343eb1 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 @@ -59,7 +59,7 @@ export const mountManagementSection = async ({ mountParams, serviceRegistry, }: MountParams) => { - const [coreStart, { data }, pluginStart] = await core.getStartServices(); + const [coreStart, { data, uiActions }, pluginStart] = await core.getStartServices(); const { element, history, setBreadcrumbs } = mountParams; if (allowedObjectTypes === undefined) { allowedObjectTypes = await getAllowedTypes(coreStart.http); @@ -88,6 +88,7 @@ export const mountManagementSection = async ({ }> -
+

Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn’t be. -

+

diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap index f977c17df41d..7ec56732ec7c 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/not_found_errors.test.tsx.snap @@ -62,7 +62,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern type 1`] =
-
+

The index pattern associated with this object no longer exists. -

-
+

+

If you know what this error means, go ahead and fix it — otherwise click the delete button above. -

+

@@ -151,7 +151,7 @@ exports[`NotFoundErrors component renders correctly for index-pattern-field type
-
+

A field associated with this object no longer exists in the index pattern. -

-
+

+

If you know what this error means, go ahead and fix it — otherwise click the delete button above. -

+

@@ -240,7 +240,7 @@ exports[`NotFoundErrors component renders correctly for search type 1`] = `
-
+

The saved search associated with this object no longer exists. -

-
+

+

If you know what this error means, go ahead and fix it — otherwise click the delete button above. -

+

@@ -329,8 +329,8 @@ exports[`NotFoundErrors component renders correctly for unknown type 1`] = `
-
-
+

+

If you know what this error means, go ahead and fix it — otherwise click the delete button above. -

+

diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx index ef16a7330410..788f2e24116f 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/intro.tsx @@ -44,12 +44,12 @@ export const Intro = () => { iconType="alert" color="warning" > -
+

-

+

); }; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx index 91f60f170717..59fb0a984606 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/not_found_errors.tsx @@ -76,13 +76,13 @@ export const NotFoundErrors = ({ type }: NotFoundErrors) => { iconType="alert" color="danger" > -
{getMessage()}
-
+

{getMessage()}

+

-

+

); }; diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx index ce1a12fdbaef..30627e69084c 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx +++ b/src/plugins/saved_objects_management/public/management_section/object_view/saved_object_view.tsx @@ -43,6 +43,8 @@ import { ISavedObjectsManagementServiceRegistry } from '../../services'; import { Header, NotFoundErrors, Intro, Form } from './components'; import { canViewInApp } from '../../lib'; import { SubmittedFormData } from '../types'; +import { UiActionsStart } from '../../../../ui_actions/public'; +import { SAVED_OBJECT_DELETE_TRIGGER } from '../../triggers'; interface SavedObjectEditionProps { id: string; @@ -51,6 +53,7 @@ interface SavedObjectEditionProps { capabilities: Capabilities; overlays: OverlayStart; notifications: NotificationsStart; + uiActions: UiActionsStart; notFoundType?: string; savedObjectsClient: SavedObjectsClientContract; history: ScopedHistory; @@ -167,9 +170,16 @@ export class SavedObjectEdition extends Component< buttonColor: 'danger', } ); + // TODO: This trigger should be maintained and emitted by the saved objects plugin + // when an obj is deleted. Tracking issue: + // https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4499 if (confirmed) { + this.props.uiActions + .getTrigger(SAVED_OBJECT_DELETE_TRIGGER) + .exec({ type, savedObjectId: id }); await savedObjectsClient.delete(type, id); - notifications.toasts.addSuccess(`Deleted '${object!.attributes.title}' ${type} object`); + + notifications.toasts.addSuccess(`Deleted ${this.formatTitle(object)} ${type} object`); this.redirectToListing(); } } @@ -179,10 +189,14 @@ export class SavedObjectEdition extends Component< const { object, type } = this.state; await savedObjectsClient.update(object!.type, object!.id, attributes, { references }); - notifications.toasts.addSuccess(`Updated '${attributes.title}' ${type} object`); + notifications.toasts.addSuccess(`Updated ${this.formatTitle(object)} ${type} object`); this.redirectToListing(); }; + formatTitle = (object: SimpleSavedObject | undefined) => { + return object?.attributes?.title ?? ''; + }; + redirectToListing() { this.props.history.push('/'); } diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap index f9091d06c691..c91fcbd7769e 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap @@ -21,43 +21,41 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = ` - - - - } - > -

- - - , - } + + + } + > +

+ + + , } - /> -

-
-
+ } + /> +

+ - - - - } - > -

- -

-
- -
- - - - } - > -

- - - , - } + + + } + > +

+ +

+
+ + + + } + > +

+ + + , } - /> -

-
-
+ } + /> +

+

- - - -    MyDashboard

@@ -167,21 +156,10 @@ exports[`Relationships from legacy app should render errors 1`] = ` hasBorder={true} >

- - - -    MyDashboard

@@ -197,7 +175,9 @@ exports[`Relationships from legacy app should render errors 1`] = ` /> } > - foo +

+ foo +

@@ -211,21 +191,10 @@ exports[`Relationships from legacy app should render index patterns normally 1`] hasBorder={true} >

- - - -    MyIndexPattern*

@@ -375,21 +344,10 @@ exports[`Relationships from legacy app should render searches normally 1`] = ` hasBorder={true} >

- - - -    MySearch

@@ -539,21 +497,10 @@ exports[`Relationships from legacy app should render visualizations normally 1`] hasBorder={true} >

- - - -    MyViz

@@ -690,6 +637,140 @@ exports[`Relationships from legacy app should render visualizations normally 1`] `; +exports[`Relationships should render augment-vis objects normally 1`] = ` + + + +

+ MyAugmentVisObject +

+
+
+ +
+ +

+ Here are the saved objects related to MyAugmentVisObject. Deleting this augment-vis affects its parent objects, but not its children. +

+
+ + +
+
+
+`; + exports[`Relationships should render dashboards normally 1`] = `

- - - -    MyDashboard

@@ -857,21 +927,10 @@ exports[`Relationships should render errors 1`] = ` hasBorder={true} >

- - - -    MyDashboard

@@ -887,7 +946,9 @@ exports[`Relationships should render errors 1`] = ` /> } > - foo +

+ foo +

@@ -901,21 +962,10 @@ exports[`Relationships should render index patterns normally 1`] = ` hasBorder={true} >

- - - -    MyIndexPattern*

@@ -1065,21 +1115,10 @@ exports[`Relationships should render searches normally 1`] = ` hasBorder={true} >

- - - -    MySearch

@@ -1229,21 +1268,10 @@ exports[`Relationships should render visualizations normally 1`] = ` hasBorder={true} >

- - - -    MyViz

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 b0dd8c269039..ad082513b277 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 @@ -917,18 +917,10 @@ export class Flyout extends Component { return ( - {legacyFileWarning && ( - - - {legacyFileWarning} - - )} - {indexPatternConflictsWarning && ( - - - {indexPatternConflictsWarning} - - )} + {legacyFileWarning && } + {legacyFileWarning} + {indexPatternConflictsWarning && } + {indexPatternConflictsWarning} ); } diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.scss b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.scss index 4b46c1244e24..99e824f3b4f3 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.scss +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.scss @@ -14,7 +14,3 @@ .savedObjectsManagementImportSummary__errorCount { color: $euiColorDangerText; } - -.savedObjectsManagementImportSummary__icon { - margin-left: $euiSizeXS; -} diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx index d78b98bdc6f0..1f21e5990c74 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.test.tsx @@ -243,6 +243,55 @@ describe('Relationships', () => { expect(component).toMatchSnapshot(); }); + it('should render augment-vis objects normally', async () => { + const props: RelationshipsProps = { + goInspectObject: () => {}, + canGoInApp: () => true, + basePath: httpServiceMock.createSetupContract().basePath, + getRelationships: jest.fn().mockImplementation(() => [ + { + type: 'visualization', + id: '1', + relationship: 'child', + meta: { + title: 'MyViz', + icon: 'visualizeApp', + editUrl: '/management/opensearch-dashboards/objects/savedVisualizations/1', + inAppUrl: { + path: '/edit/1', + uiCapabilitiesPath: 'visualize.show', + }, + }, + }, + ]), + savedObject: { + id: '1', + type: 'augment-vis', + attributes: {}, + references: [], + meta: { + title: 'MyAugmentVisObject', + icon: 'savedObject', + editUrl: '/management/opensearch-dashboards/objects/savedAugmentVis/1', + }, + }, + close: jest.fn(), + }; + + const component = shallowWithI18nProvider(); + + // Make sure we are showing loading + expect(component.find('EuiLoadingSpinner').length).toBe(1); + + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + + expect(props.getRelationships).toHaveBeenCalled(); + expect(component).toMatchSnapshot(); + }); + it('should render dashboards normally', async () => { const props: RelationshipsProps = { goInspectObject: () => {}, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx index ff42351d83af..0115111da0ac 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/relationships.tsx @@ -116,7 +116,7 @@ export class Relationships extends Component - {error} +

{error}

); } @@ -336,18 +336,8 @@ export class Relationships extends Component - -

- - - -    - {savedObject.meta.title || getDefaultTitle(savedObject)} -

+ +

{savedObject.meta.title || getDefaultTitle(savedObject)}

diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_edition_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_edition_page.tsx index 51868e3e12c8..49513e484272 100644 --- a/src/plugins/saved_objects_management/public/management_section/saved_objects_edition_page.tsx +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_edition_page.tsx @@ -33,16 +33,19 @@ import { useParams, useLocation } from 'react-router-dom'; import { parse } from 'query-string'; import { i18n } from '@osd/i18n'; import { CoreStart, ChromeBreadcrumb, ScopedHistory } from 'src/core/public'; +import { UiActionsStart } from 'src/plugins/ui_actions/public'; import { ISavedObjectsManagementServiceRegistry } from '../services'; import { SavedObjectEdition } from './object_view'; const SavedObjectsEditionPage = ({ coreStart, + uiActionsStart, serviceRegistry, setBreadcrumbs, history, }: { coreStart: CoreStart; + uiActionsStart: UiActionsStart; serviceRegistry: ISavedObjectsManagementServiceRegistry; setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; history: ScopedHistory; @@ -79,6 +82,7 @@ const SavedObjectsEditionPage = ({ savedObjectsClient={coreStart.savedObjects.client} overlays={coreStart.overlays} notifications={coreStart.notifications} + uiActions={uiActionsStart} capabilities={capabilities} notFoundType={query.notFound as string} history={history} diff --git a/src/plugins/saved_objects_management/public/plugin.test.ts b/src/plugins/saved_objects_management/public/plugin.test.ts index e55760846a5f..c8e762f73dcc 100644 --- a/src/plugins/saved_objects_management/public/plugin.test.ts +++ b/src/plugins/saved_objects_management/public/plugin.test.ts @@ -32,6 +32,7 @@ import { coreMock } from '../../../core/public/mocks'; import { homePluginMock } from '../../home/public/mocks'; import { managementPluginMock } from '../../management/public/mocks'; import { dataPluginMock } from '../../data/public/mocks'; +import { uiActionsPluginMock } from '../../ui_actions/public/mocks'; import { SavedObjectsManagementPlugin } from './plugin'; describe('SavedObjectsManagementPlugin', () => { @@ -48,8 +49,13 @@ describe('SavedObjectsManagementPlugin', () => { }); const homeSetup = homePluginMock.createSetupContract(); const managementSetup = managementPluginMock.createSetupContract(); + const uiActionsSetup = uiActionsPluginMock.createSetupContract(); - await plugin.setup(coreSetup, { home: homeSetup, management: managementSetup }); + await plugin.setup(coreSetup, { + home: homeSetup, + management: managementSetup, + uiActions: uiActionsSetup, + }); expect(homeSetup.featureCatalogue.register).toHaveBeenCalledTimes(1); expect(homeSetup.featureCatalogue.register).toHaveBeenCalledWith( diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index ec7d64ed700c..14beb73386a8 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -33,11 +33,13 @@ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { VisBuilderStart } from '../../vis_builder/public'; import { ManagementSetup } from '../../management/public'; +import { UiActionsSetup, UiActionsStart } from '../../ui_actions/public'; import { DataPublicPluginStart } from '../../data/public'; import { DashboardStart } from '../../dashboard/public'; import { DiscoverStart } from '../../discover/public'; import { HomePublicPluginSetup, FeatureCatalogueCategory } from '../../home/public'; import { VisualizationsStart } from '../../visualizations/public'; +import { VisAugmenterStart } from '../../vis_augmenter/public'; import { SavedObjectsManagementActionService, SavedObjectsManagementActionServiceSetup, @@ -52,6 +54,7 @@ import { ISavedObjectsManagementServiceRegistry, } from './services'; import { registerServices } from './register_services'; +import { bootstrap } from './ui_actions_bootstrap'; export interface SavedObjectsManagementPluginSetup { actions: SavedObjectsManagementActionServiceSetup; @@ -69,14 +72,17 @@ export interface SavedObjectsManagementPluginStart { export interface SetupDependencies { management: ManagementSetup; home?: HomePublicPluginSetup; + uiActions: UiActionsSetup; } export interface StartDependencies { data: DataPublicPluginStart; dashboard?: DashboardStart; visualizations?: VisualizationsStart; + visAugmenter?: VisAugmenterStart; discover?: DiscoverStart; visBuilder?: VisBuilderStart; + uiActions: UiActionsStart; } export class SavedObjectsManagementPlugin @@ -94,7 +100,7 @@ export class SavedObjectsManagementPlugin public setup( core: CoreSetup, - { home, management }: SetupDependencies + { home, management, uiActions }: SetupDependencies ): SavedObjectsManagementPluginSetup { const actionSetup = this.actionService.setup(); const columnSetup = this.columnService.setup(); @@ -121,7 +127,7 @@ export class SavedObjectsManagementPlugin opensearchDashboardsSection.registerApp({ id: 'objects', title: i18n.translate('savedObjectsManagement.managementSectionLabel', { - defaultMessage: 'Saved Objects', + defaultMessage: 'Saved objects', }), order: 1, mount: async (mountParams) => { @@ -134,6 +140,9 @@ export class SavedObjectsManagementPlugin }, }); + // sets up the context mappings and registers any triggers/actions for the plugin + bootstrap(uiActions); + // depends on `getStartServices`, should not be awaited registerServices(this.serviceRegistry, core.getStartServices); @@ -145,7 +154,7 @@ export class SavedObjectsManagementPlugin }; } - public start(core: CoreStart, { data }: StartDependencies) { + public start(core: CoreStart, { data, uiActions }: StartDependencies) { const actionStart = this.actionService.start(); const columnStart = this.columnService.start(); const namespaceStart = this.namespaceService.start(); diff --git a/src/plugins/saved_objects_management/public/register_services.ts b/src/plugins/saved_objects_management/public/register_services.ts index 514ab66a4595..1b11eb578547 100644 --- a/src/plugins/saved_objects_management/public/register_services.ts +++ b/src/plugins/saved_objects_management/public/register_services.ts @@ -36,7 +36,10 @@ export const registerServices = async ( registry: ISavedObjectsManagementServiceRegistry, getStartServices: StartServicesAccessor ) => { - const [, { dashboard, visualizations, discover, visBuilder }] = await getStartServices(); + const [ + , + { dashboard, visualizations, visAugmenter, discover, visBuilder }, + ] = await getStartServices(); if (dashboard) { registry.register({ @@ -54,6 +57,14 @@ export const registerServices = async ( }); } + if (visAugmenter) { + registry.register({ + id: 'savedAugmentVis', + title: 'augmentVis', + service: visAugmenter.savedAugmentVisLoader, + }); + } + if (discover) { registry.register({ id: 'savedSearches', diff --git a/src/plugins/saved_objects_management/public/triggers/index.ts b/src/plugins/saved_objects_management/public/triggers/index.ts new file mode 100644 index 000000000000..001864544cd3 --- /dev/null +++ b/src/plugins/saved_objects_management/public/triggers/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { + SAVED_OBJECT_DELETE_TRIGGER, + savedObjectDeleteTrigger, +} from './saved_object_delete_trigger'; diff --git a/src/plugins/saved_objects_management/public/triggers/saved_object_delete_trigger.ts b/src/plugins/saved_objects_management/public/triggers/saved_object_delete_trigger.ts new file mode 100644 index 000000000000..c9104ec4176a --- /dev/null +++ b/src/plugins/saved_objects_management/public/triggers/saved_object_delete_trigger.ts @@ -0,0 +1,24 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { Trigger } from '../../../ui_actions/public'; + +/** + * TODO: This action is currently being used behind-the-scenes in the vis_augmenter plugin + * to clean up related augment-vis saved objects when a visualization is deleted. + * This should be moved and maintained by the saved objects plugin. Tracking issue: + * https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4499 + */ +export const SAVED_OBJECT_DELETE_TRIGGER = 'SAVED_OBJECT_DELETE_TRIGGER'; +export const savedObjectDeleteTrigger: Trigger<'SAVED_OBJECT_DELETE_TRIGGER'> = { + id: SAVED_OBJECT_DELETE_TRIGGER, + title: i18n.translate('savedObjectsManagement.triggers.savedObjectDeleteTitle', { + defaultMessage: 'Saved object delete', + }), + description: i18n.translate('savedObjectsManagement.triggers.savedObjectDeleteDescription', { + defaultMessage: 'Perform additional actions after deleting a saved object', + }), +}; diff --git a/src/plugins/saved_objects_management/public/ui_actions_bootstrap.ts b/src/plugins/saved_objects_management/public/ui_actions_bootstrap.ts new file mode 100644 index 000000000000..e005ba660dee --- /dev/null +++ b/src/plugins/saved_objects_management/public/ui_actions_bootstrap.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { UiActionsSetup } from '../../ui_actions/public'; +import { SAVED_OBJECT_DELETE_TRIGGER, savedObjectDeleteTrigger } from './triggers'; + +export interface SavedObjectDeleteContext { + type: string; + savedObjectId: string; +} + +declare module '../../ui_actions/public' { + export interface TriggerContextMapping { + [SAVED_OBJECT_DELETE_TRIGGER]: SavedObjectDeleteContext; + } +} + +export const bootstrap = (uiActions: UiActionsSetup) => { + uiActions.registerTrigger(savedObjectDeleteTrigger); +}; diff --git a/src/plugins/telemetry/common/constants.ts b/src/plugins/telemetry/common/constants.ts index 626f326fc16c..f12e38f91072 100644 --- a/src/plugins/telemetry/common/constants.ts +++ b/src/plugins/telemetry/common/constants.ts @@ -42,7 +42,7 @@ export const getConfigTelemetryDesc = () => { // Can't find where it's used but copying it over from the legacy code just in case... return i18n.translate('telemetry.telemetryConfigDescription', { defaultMessage: - 'Help us improve the OpenSearch Stack by providing usage statistics for basic features. We will not share this data outside of Elastic.', + 'Help us improve the OpenSearch Stack by providing usage statistics for basic features. We will not share this data outside of OpenSearch.', }); }; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index f8dc8b7b8ae9..c4ff960b62e6 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -1337,6 +1337,12 @@ "visualization:tileMap:maxPrecision": { "type": "long" }, + "visualization:enablePluginAugmentation": { + "type": "boolean" + }, + "visualization:enablePluginAugmentation.maxPluginObjects": { + "type": "number" + }, "securitySolution:ipReputationLinks": { "type": "text" }, diff --git a/src/plugins/ui_actions/README.md b/src/plugins/ui_actions/README.md index 28e3b2d63d2e..4431a47a06ed 100644 --- a/src/plugins/ui_actions/README.md +++ b/src/plugins/ui_actions/README.md @@ -97,3 +97,12 @@ Use the UI actions explorer in the Developer examples to learn more about the se ```sh yarn start --run-examples ``` + +## Action Properties + +Refer to [./public/actions/action.ts](./public/actions/action.ts) for all properties, keeping in mind it extends the [presentable](./public/util/presentable.ts) interface. Here are some properties that provide special functionality and customization. + +- `order` is used when there is more than one action matched to a trigger and within context menus. Higher numbers are displayed first. +- `getDisplayName` is a function that can return either a string or a JSX element. Returning a JSX element allows flexibility with formatting. +- `getIconType` can be used to add an icon before the display name. +- `grouping` determines where this item should appear as a submenu. Each group can also contain a category, which is used within context menus to organize similar groups into the same section of the menu. See examples explorer for more details about what this looks like within a context menu. diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts index b9afca9fb99c..e70561bea221 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts @@ -448,3 +448,123 @@ test('groups with deep nesting', async () => { ] `); }); + +// Tests with: +// a regular action +// a group with 2 actions uncategorized +// a group with 2 actions with a category of "test-category" and low order of 10 +// a group with 1 actions with a category of "test-category" and high order of 20 +test('groups with categories and order', async () => { + const grouping1 = [ + { + id: 'test-group', + getDisplayName: () => 'Test group', + getIconType: () => 'bell', + }, + ]; + const grouping2 = [ + { + id: 'test-group-2', + getDisplayName: () => 'Test group 2', + getIconType: () => 'bell', + category: 'test-category', + order: 10, + }, + ]; + const grouping3 = [ + { + id: 'test-group-3', + getDisplayName: () => 'Test group 3', + getIconType: () => 'bell', + category: 'test-category', + order: 20, + }, + ]; + + const actions = [ + createTestAction({ + dispayName: 'Foo 1', + }), + createTestAction({ + dispayName: 'Bar 1', + grouping: grouping1, + }), + createTestAction({ + dispayName: 'Bar 2', + grouping: grouping1, + }), + createTestAction({ + dispayName: 'Qux 1', + grouping: grouping2, + }), + createTestAction({ + dispayName: 'Qux 2', + grouping: grouping2, + }), + // It is expected that, because there is only 1 action within this group, + // it will be added to the mainMenu as a single item, but next to other + // groups of the same category. When a group has a category, but only one + // item, we just add that single item; otherwise, we add a link to the group + createTestAction({ + dispayName: 'Waldo 1', + grouping: grouping3, + }), + ]; + const menu = await buildContextMenuForActions({ + actions: actions.map((action) => ({ action, context: {}, trigger: 'TEST' as any })), + }); + + expect(menu.map(resultMapper)).toMatchInlineSnapshot(` + Array [ + Object { + "items": Array [ + Object { + "name": "Foo 1", + }, + Object { + "isSeparator": true, + }, + Object { + "name": "Test group", + }, + Object { + "isSeparator": true, + }, + Object { + "name": "Waldo 1", + }, + Object { + "name": "Test group 2", + }, + ], + }, + Object { + "items": Array [ + Object { + "name": "Bar 1", + }, + Object { + "name": "Bar 2", + }, + ], + }, + Object { + "items": Array [ + Object { + "name": "Qux 1", + }, + Object { + "name": "Qux 2", + }, + ], + }, + Object { + "items": Array [ + Object { + "name": "Waldo 1", + }, + ], + }, + ] + `); +}); diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx index 6d69be1f3faa..81710767e0a9 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx @@ -64,6 +64,8 @@ type PanelDescriptor = EuiContextMenuPanelDescriptor & { _level?: number; _icon?: string; items: ItemDescriptor[]; + _category?: string; + _order?: number; }; const onClick = (action: Action, context: ActionExecutionContext, close: () => void) => ( @@ -125,7 +127,7 @@ const removeItemMetaFields = (items: ItemDescriptor[]): EuiContextMenuPanelItemD const removePanelMetaFields = (panels: PanelDescriptor[]): EuiContextMenuPanelDescriptor[] => { const euiPanels: EuiContextMenuPanelDescriptor[] = []; for (const panel of panels) { - const { _level: omit, _icon: omit2, ...rest } = panel; + const { _level: omit, _icon: omit2, _category: omit3, _order: omit4, ...rest } = panel; euiPanels.push({ ...rest, items: removeItemMetaFields(rest.items) }); } return euiPanels; @@ -179,6 +181,8 @@ export async function buildContextMenuForActions({ items: [], _level: i, _icon: group.getIconType ? group.getIconType(context) : 'empty', + _category: group.category, + _order: group.order, }; // If there are multiple groups and this is not the first group, @@ -231,17 +235,57 @@ export async function buildContextMenuForActions({ // Any additional items are hidden behind a "more" item wrapMainPanelItemsIntoSubmenu(panels, 'mainMenu'); + // This will be used to store items that eventually are placed into the + // mainMenu panel. Specifying a category allows for placing groups into the + // mainMenu so they appear without the separator between them. + const categories = {}; + for (const panel of Object.values(panels)) { - // If the panel is a root-level panel, such as the parent of a group, - // then create mainMenu item for this panel - if (panel._level === 0) { + // Do nothing if not root-level panel, such as the parent of a group + if (panel._level !== 0) { + continue; + } + + // Proceed to create mainMenu item for this panel + + // If a category is specified, store either a link to the panel or the + // item within to that category. We will deal with the category after + // looping through all panels. + if (panel._category) { + // Create array to store category items + if (!categories[panel._category]) { + categories[panel._category] = []; + } + + // If multiple items in the panel, store a link to this panel into the category. + // Otherwise, just store the single item into the category. + if (panel.items.length > 1) { + categories[panel._category].push({ + order: panel._order, + items: [ + { + name: panel.title || panel.id, + icon: panel._icon || 'empty', + panel: panel.id, + }, + ], + }); + } else { + categories[panel._category].push({ + order: panel._order || 0, + items: panel.items, + }); + } + } else { + // If no category, continue with adding items to the mainMenu + // Add separator with unique key if needed if (panels.mainMenu.items.length) { panels.mainMenu.items.push({ isSeparator: true, key: `${panel.id}separator` }); } // If a panel has more than one child, then allow items to be grouped - // and link to it in the mainMenu. Otherwise, flatten the group. + // and link to it in the mainMenu. Otherwise, link to the single item. // Note: this only happens on the root level panels, not for inner groups. if (panel.items.length > 1) { panels.mainMenu.items.push({ @@ -255,6 +299,27 @@ export async function buildContextMenuForActions({ } } + // For each category, add a separator before each one and then add category items. + // This is for the mainMenu panel. + Object.keys(categories).forEach((key) => { + // Get the items sorted by group order, allowing for groups within categories + // to be ordered. A category consists of an order and its items. + // Higher orders are sorted to the top. + const sortedEntries = categories[key].sort((a, b) => b.order - a.order); + const sortedItems = sortedEntries.reduce( + (items, category) => [...items, ...category.items], + [] + ); + + // Add separator with unique key if needed + if (panels.mainMenu.items.length) { + panels.mainMenu.items.push({ isSeparator: true, key: `${key}separator` }); + } + + panels.mainMenu.items.push(...sortedItems); + }); + const panelList = Object.values(panels); + return removePanelMetaFields(panelList); } diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index 3560f473d33b..489cb5eee363 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -61,6 +61,8 @@ export { visualizeFieldTrigger, VISUALIZE_GEO_FIELD_TRIGGER, visualizeGeoFieldTrigger, + EXTERNAL_ACTION_TRIGGER, + externalActionTrigger, } from './triggers'; export { TriggerContextMapping, diff --git a/src/plugins/ui_actions/public/triggers/external_action_trigger.ts b/src/plugins/ui_actions/public/triggers/external_action_trigger.ts new file mode 100644 index 000000000000..37af88f9b545 --- /dev/null +++ b/src/plugins/ui_actions/public/triggers/external_action_trigger.ts @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { Trigger } from '.'; + +export const EXTERNAL_ACTION_TRIGGER = 'EXTERNAL_ACTION_TRIGGER'; +export const externalActionTrigger: Trigger<'EXTERNAL_ACTION_TRIGGER'> = { + id: EXTERNAL_ACTION_TRIGGER, + title: i18n.translate('uiActions.triggers.externalActionTitle', { + defaultMessage: 'Single click', + }), + description: i18n.translate('uiActions.triggers.externalActionDescription', { + defaultMessage: + 'A data point click on the visualization used to trigger external action like show flyout, etc.', + }), +}; diff --git a/src/plugins/ui_actions/public/triggers/index.ts b/src/plugins/ui_actions/public/triggers/index.ts index 2d012df76e08..0fcbbc4ee3fa 100644 --- a/src/plugins/ui_actions/public/triggers/index.ts +++ b/src/plugins/ui_actions/public/triggers/index.ts @@ -36,4 +36,5 @@ export * from './value_click_trigger'; export * from './apply_filter_trigger'; export * from './visualize_field_trigger'; export * from './visualize_geo_field_trigger'; +export * from './external_action_trigger'; export * from './default_trigger'; diff --git a/src/plugins/ui_actions/public/util/presentable.ts b/src/plugins/ui_actions/public/util/presentable.ts index 428644e1c2c6..9aaeada8a16e 100644 --- a/src/plugins/ui_actions/public/util/presentable.ts +++ b/src/plugins/ui_actions/public/util/presentable.ts @@ -94,6 +94,14 @@ export interface PresentableGroup Pick, 'getDisplayName' | 'getDisplayNameTooltip' | 'getIconType' | 'order'> > { id: string; + /** + * This allows groups to be categorized with other groups. Within a UI action + * context menu, this means that an item, which links to a group, will be + * placed in the menu adjacent to similar items that link to groups of the + * same category. + * See PanelGroupOptionsAndContextActions example to learn more. + */ + category?: string; } export type PresentableGrouping = Array>; diff --git a/src/plugins/vis_augmenter/README.md b/src/plugins/vis_augmenter/README.md new file mode 100644 index 000000000000..a797221ecd08 --- /dev/null +++ b/src/plugins/vis_augmenter/README.md @@ -0,0 +1,71 @@ +## Vis Augmenter + +### Overview + +The feature introduced in [#4361](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4361) allows for plugins to be able to display additional data on a visualization. The framework for how that is done, including all of the interfaces, type definitions, helper functions, and services used, are maintained in this plugin. It also registers new saved object types and expression types that plugins use to standardize how data is formatted and visualized on the charts. + +### Eligibility + +Currently, this augmenting framework is only eligible for line visualizations, with a single date histogram x axis. There is future plans to expand this to other types of visualizations, as well as other ways that visualizations may be augmented, such as overlaying forecasting data. + +### Framework + +The main idea is that plugins can hook into the render lifecycle of a visualization, such that when the original source datapoints are being fetched, plugins can also fetch data. All of this can then be combined and visualized cohesively on a chart. This process can be broken down into a few main steps: + +1. Plugins implement a way to associate a plugin resource to a visualization. In the background, this means creating an `augment-vis` saved object linking the two. +2. Vis Augmenter will fetch any `augment-vis` objects that reference a particular visualization. +3. Vis Augmenter will run the plugin-registered expression function, along with any arguments, that is persisted in the saved object. +4. Vis Augmenter will combine all of the `VisLayer` results from the expression functions. +5. Vis Augmenter will update the source datatable with every `VisLayer`, dependent on the specific `VisLayer` type. +6. Visualization is rendered with the original data & augmented plugin data. + +### `augment-vis` saved object + +This is a new saved object type introduced with the primary purpose of maintaining an association of a plugin resource (e.g., anomaly detector, alerting monitor) to a visualization. It also contains the plugin-registered expression function that will be executed when fetching data for that particular resource, when rendering the visualization. The advantages of using saved objects to maintain these relationships is it keeps this relationship strictly a Dashboards-only feature, without coupling anything with the objects stored in OpenSearch. It also lets us use the concept of multitenancy to isolate these associations across different tenants. + +### `VisLayer`s + +`VisLayer` is the generic interface for a type of augmentation done on a visualization. The main idea is any plugin can hook into the rendering workflow of a visualization and have it fetch `VisLayer`s. This plugin will handle the processing of `VisLayer`s of different types, and how each type will be rendered consistently on a visualization. Currently, the only introduced one is `PointInTimeEventsVisLayer`. This will render a red triangle event datapoint below a source visualization, aligned with the visualization's temporal axis. + +### View events flyout + +This is the primary UI for providing a more detailed view on `VisLayer`s for a particular visualization. See the corresponding [README](src/plugins/vis_augmenter/public/view_events_flyout/README.md) for details. + +### The `stats` API + +There is a new server-side `stats` API which can be used for retrieving feature usage metrics. It gathers all of the `augment-vis` saved objects and aggregates them to get an idea of how many associations are created between which plugins and which visualizations. For more details on the API, see the [PR](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4006). + +Example usage: + +``` +curl localhost:5601/api/vis_augmenter/stats +{ + "total_objs": 2, + "obj_breakdown": { + "origin_plugin": { "anomalyDetectionDashboards": 2 }, + "plugin_resource_type": { "Anomaly Detectors": 2 }, + "plugin_resource_id": { "detector-1-id": 1, "detector-2-id": 1 }, + "visualization_id": { "visualization-1-id": 2 } + } +} +``` + +### Settings + +The feature can be toggled on/off entirely through the `vis_augmenter.pluginAugmentationEnabled` setting in the `opensearch_dashboards.yml` config file. If enabled, there are additional fields that can be set in the advanced settings: +`visualization.enablePluginAugmentation` to toggle the feature on/off. +`visualization.enablePluginAugmentation.maxPluginObjects` to adjust the number of associations allowed per visualization. For example, to keep users from creating too many plugin resources and associations to visualizations, this value can be lowered. + +For more details, see the [PR](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3961). + +### Steps for plugin integration + +For an external plugin to utilize the Vis Augmenter plugin and its rendering framework, there are a few main steps needed: + +1. Provide UX for handling associations between a visualization and plugin resources. There are examples in [Anomaly Detection](https://github.com/opensearch-project/anomaly-detection-dashboards-plugin/issues/400) and [Alerting](https://github.com/opensearch-project/alerting-dashboards-plugin/issues/457). This is where the bulk of the effort is needed. While there is no very strict requirements, there should be UX flows for creating, adding, and removing associated plugin resources to the visualization. Behind-the-scenes, this means making saved object API calls to handle CRUD operations of the `augment-vis` saved objects. Another important part is implementing & registering a `UIAction` so that there is a visible option under the visualization context menu to maintain associations. This is the current way that Anomaly Detection and Alerting inject their UX components into core Dashboards. + + > It is worth calling out that currently there is no other registration being done by the plugins to potentially leverage common UX components or user flows, such as what's done in the Saved Objects Management plugin for different saved object types. There is improvements that can be done to decrease plugin responsibility and prevent duplicate code by persisting a lot of these common flows within Vis Augmenter. Given that this is an initial release with a lot of uncertainty on how the flows may differ across plugins, or what becomes the most important or common user flows, this was left as an open item for now. + +2. Implement & register an expression function of type `vis_layers` that will fetch plugin data and format it into a `VisLayer`. This is what will be executed when a visualization is rendered and all of the chart's source data is being retrieved. It is important that the function does not simply return its own `VisLayer` result, but rather appends it to the list of input `VisLayer`s. By following this pattern, it allows any number of plugins to execute any number of functions in any sequence, to all produce the same final set of `VisLayer`s for a particular visualization. For an example function, check out Anomaly Detection's [overlay_anomalies](https://github.com/opensearch-project/anomaly-detection-dashboards-plugin/blob/main/public/expressions/overlay_anomalies.ts). + +3. Define constant values to be included in the `augment-vis` saved objects. For example, all objects from a particular plugin should have consistent values for `originPlugin`, `expressionFn`, and `pluginEventType`, as well as follow a consistent pattern for populating `pluginResource` values, such as `urlPath`. For details on each specific field, see [here](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/src/plugins/vis_augmenter/public/types.ts). For an example, check out constants used by the Anomaly Detection plugin [here](https://github.com/opensearch-project/anomaly-detection-dashboards-plugin/blob/main/public/expressions/constants.ts). diff --git a/src/plugins/vis_augmenter/common/augment_vis_saved_object_attributes.ts b/src/plugins/vis_augmenter/common/augment_vis_saved_object_attributes.ts new file mode 100644 index 000000000000..824f35c6e112 --- /dev/null +++ b/src/plugins/vis_augmenter/common/augment_vis_saved_object_attributes.ts @@ -0,0 +1,32 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectAttributes } from 'opensearch-dashboards/server'; + +export interface AugmentVisSavedObjectAttributes extends SavedObjectAttributes { + id: string; + title: string; + description?: string; + originPlugin: string; + pluginResource: { + type: string; + id: string; + }; + visLayerExpressionFn: { + type: string; + name: string; + }; + version: number; + // Following fields are optional since they will get set/removed during the extraction/injection + // of the vis reference + visName?: string; + visId?: string; + visReference?: { + id: string; + name: string; + }; + // Error may be populated if there is some issue when parsing the attribute values + error?: string; +} diff --git a/src/plugins/vis_augmenter/common/constants.ts b/src/plugins/vis_augmenter/common/constants.ts new file mode 100644 index 000000000000..438e2b9c5ba3 --- /dev/null +++ b/src/plugins/vis_augmenter/common/constants.ts @@ -0,0 +1,13 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const APP_PATH = { + STATS: '/stats', +}; +export const APP_API = '/api/vis_augmenter'; + +export const PLUGIN_AUGMENTATION_ENABLE_SETTING = 'visualization:enablePluginAugmentation'; +export const PLUGIN_AUGMENTATION_MAX_OBJECTS_SETTING = + 'visualization:enablePluginAugmentation.maxPluginObjects'; diff --git a/src/plugins/vis_augmenter/common/index.ts b/src/plugins/vis_augmenter/common/index.ts new file mode 100644 index 000000000000..9762ce68770e --- /dev/null +++ b/src/plugins/vis_augmenter/common/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './constants'; +export { AugmentVisSavedObjectAttributes } from './augment_vis_saved_object_attributes'; diff --git a/src/plugins/vis_augmenter/config.ts b/src/plugins/vis_augmenter/config.ts new file mode 100644 index 000000000000..12b9854f451a --- /dev/null +++ b/src/plugins/vis_augmenter/config.ts @@ -0,0 +1,12 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { schema, TypeOf } from '@osd/config-schema'; + +export const configSchema = schema.object({ + pluginAugmentationEnabled: schema.boolean({ defaultValue: true }), +}); + +export type VisAugmenterPluginConfigType = TypeOf; diff --git a/src/plugins/vis_augmenter/opensearch_dashboards.json b/src/plugins/vis_augmenter/opensearch_dashboards.json new file mode 100644 index 000000000000..9026bdd24859 --- /dev/null +++ b/src/plugins/vis_augmenter/opensearch_dashboards.json @@ -0,0 +1,16 @@ +{ + "id": "visAugmenter", + "version": "opensearchDashboards", + "server": true, + "ui": true, + "requiredPlugins": [ + "data", + "savedObjects", + "opensearchDashboardsUtils", + "expressions", + "visualizations", + "uiActions", + "embeddable" + ], + "requiredBundles": ["opensearchDashboardsReact", "savedObjectsManagement"] +} diff --git a/src/plugins/vis_augmenter/public/actions/index.ts b/src/plugins/vis_augmenter/public/actions/index.ts new file mode 100644 index 000000000000..893032f86813 --- /dev/null +++ b/src/plugins/vis_augmenter/public/actions/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { + PLUGIN_RESOURCE_DELETE_ACTION, + PluginResourceDeleteAction, +} from './plugin_resource_delete_action'; +export { SAVED_OBJECT_DELETE_ACTION, SavedObjectDeleteAction } from './saved_object_delete_action'; diff --git a/src/plugins/vis_augmenter/public/actions/plugin_resource_delete_action.test.ts b/src/plugins/vis_augmenter/public/actions/plugin_resource_delete_action.test.ts new file mode 100644 index 000000000000..907b383c60a0 --- /dev/null +++ b/src/plugins/vis_augmenter/public/actions/plugin_resource_delete_action.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createPointInTimeEventsVisLayer } from '../mocks'; +import { generateAugmentVisSavedObject } from '../saved_augment_vis'; +import { PluginResourceDeleteAction } from './plugin_resource_delete_action'; + +jest.mock('src/plugins/vis_augmenter/public/services.ts', () => { + return { + getSavedAugmentVisLoader: () => { + return { + delete: () => {}, + findAll: () => { + return { + hits: [], + }; + }, + }; + }, + }; +}); + +const sampleSavedObj = generateAugmentVisSavedObject( + 'test-id', + { + type: 'PointInTimeEvents', + name: 'test-fn-name', + args: {}, + }, + 'test-vis-id', + 'test-origin-plugin', + { + type: 'test-resource-type', + id: 'test-resource-id', + } +); + +const sampleVisLayer = createPointInTimeEventsVisLayer(); + +describe('SavedObjectDeleteAction', () => { + it('is incompatible with invalid saved obj list', async () => { + const action = new PluginResourceDeleteAction(); + const visLayers = [sampleVisLayer]; + // @ts-ignore + expect(await action.isCompatible({ savedObjs: null, visLayers })).toBe(false); + // @ts-ignore + expect(await action.isCompatible({ savedObjs: undefined, visLayers })).toBe(false); + expect(await action.isCompatible({ savedObjs: [], visLayers })).toBe(false); + }); + + it('is incompatible with invalid vislayer list', async () => { + const action = new PluginResourceDeleteAction(); + const savedObjs = [sampleSavedObj]; + // @ts-ignore + expect(await action.isCompatible({ savedObjs, visLayers: null })).toBe(false); + // @ts-ignore + expect(await action.isCompatible({ savedObjs, visLayers: undefined })).toBe(false); + expect(await action.isCompatible({ savedObjs, visLayers: [] })).toBe(false); + }); + + it('execute throws error if incompatible saved objs list', async () => { + const action = new PluginResourceDeleteAction(); + async function check(savedObjs: any, visLayers: any) { + await action.execute({ savedObjs, visLayers }); + } + await expect(check(null, [sampleVisLayer])).rejects.toThrow(Error); + }); + + it('execute throws error if incompatible vis layer list', async () => { + const action = new PluginResourceDeleteAction(); + async function check(savedObjs: any, visLayers: any) { + await action.execute({ savedObjs, visLayers }); + } + await expect(check([sampleSavedObj], null)).rejects.toThrow(Error); + }); + + it('execute is successful if valid saved obj and vis layer lists', async () => { + const action = new PluginResourceDeleteAction(); + async function check(savedObjs: any, visLayers: any) { + await action.execute({ savedObjs, visLayers }); + } + await expect(check([sampleSavedObj], [sampleVisLayer])).resolves; + }); + + it('Returns display name', async () => { + const action = new PluginResourceDeleteAction(); + expect(action.getDisplayName()).toBeDefined(); + }); + + it('Returns icon type', async () => { + const action = new PluginResourceDeleteAction(); + expect(action.getIconType()).toBeDefined(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/actions/plugin_resource_delete_action.ts b/src/plugins/vis_augmenter/public/actions/plugin_resource_delete_action.ts new file mode 100644 index 000000000000..6e3939820d28 --- /dev/null +++ b/src/plugins/vis_augmenter/public/actions/plugin_resource_delete_action.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isEmpty } from 'lodash'; +import { i18n } from '@osd/i18n'; +import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; +import { Action, IncompatibleActionError } from '../../../ui_actions/public'; +import { getSavedAugmentVisLoader } from '../services'; +import { PluginResourceDeleteContext } from '../ui_actions_bootstrap'; +import { cleanupStaleObjects } from '../utils'; + +export const PLUGIN_RESOURCE_DELETE_ACTION = 'PLUGIN_RESOURCE_DELETE_ACTION'; + +export class PluginResourceDeleteAction implements Action { + public readonly type = PLUGIN_RESOURCE_DELETE_ACTION; + public readonly id = PLUGIN_RESOURCE_DELETE_ACTION; + public order = 1; + + public getIconType(): EuiIconType { + return `trash`; + } + + public getDisplayName() { + return i18n.translate('dashboard.actions.deleteSavedObject.name', { + defaultMessage: + 'Clean up all augment-vis saved objects associated to the deleted visualization', + }); + } + + public async isCompatible({ savedObjs, visLayers }: PluginResourceDeleteContext) { + return !isEmpty(savedObjs) && !isEmpty(visLayers); + } + + /** + * If we have just collected all of the saved objects and generated vis layers, + * sweep through them all and if any of the resources are deleted, delete those + * corresponding saved objects + */ + public async execute({ savedObjs, visLayers }: PluginResourceDeleteContext) { + if (!(await this.isCompatible({ savedObjs, visLayers }))) { + throw new IncompatibleActionError(); + } + cleanupStaleObjects(savedObjs, visLayers, getSavedAugmentVisLoader()); + } +} diff --git a/src/plugins/vis_augmenter/public/actions/saved_object_delete_action.test.ts b/src/plugins/vis_augmenter/public/actions/saved_object_delete_action.test.ts new file mode 100644 index 000000000000..c8c623fae3a9 --- /dev/null +++ b/src/plugins/vis_augmenter/public/actions/saved_object_delete_action.test.ts @@ -0,0 +1,98 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectDeleteAction } from './saved_object_delete_action'; +import services from '../services'; + +jest.mock('src/plugins/vis_augmenter/public/services.ts', () => { + return { + getSavedAugmentVisLoader: () => { + return { + delete: () => {}, + findAll: () => { + return { + hits: [], + }; + }, + }; + }, + getUISettings: () => { + return { + get: (config: string) => { + switch (config) { + case 'visualization:enablePluginAugmentation': + return true; + case 'visualization:enablePluginAugmentation.maxPluginObjects': + return 10; + default: + throw new Error(`Accessing ${config} is not supported in the mock.`); + } + }, + }; + }, + }; +}); + +describe('SavedObjectDeleteAction', () => { + it('is incompatible with invalid types', async () => { + const action = new SavedObjectDeleteAction(); + const savedObjectId = '1234'; + // @ts-ignore + expect(await action.isCompatible({ type: null, savedObjectId })).toBe(false); + // @ts-ignore + expect(await action.isCompatible({ type: undefined, savedObjectId })).toBe(false); + expect(await action.isCompatible({ type: '', savedObjectId })).toBe(false); + expect(await action.isCompatible({ type: 'not-visualization-type', savedObjectId })).toBe( + false + ); + expect(await action.isCompatible({ type: 'savedSearch', savedObjectId })).toBe(false); + }); + + it('is incompatible with invalid saved obj ids', async () => { + const action = new SavedObjectDeleteAction(); + const type = 'visualization'; + // @ts-ignore + expect(await action.isCompatible({ type, savedObjectId: null })).toBe(false); + // @ts-ignore + expect(await action.isCompatible({ type, savedObjectId: undefined })).toBe(false); + expect(await action.isCompatible({ type, savedObjectId: '' })).toBe(false); + }); + + it('execute throws error if incompatible type', async () => { + const action = new SavedObjectDeleteAction(); + async function check(type: any, id: any) { + await action.execute({ type, savedObjectId: id }); + } + await expect(check(null, '1234')).rejects.toThrow(Error); + }); + + it('execute throws error if incompatible saved obj id', async () => { + const action = new SavedObjectDeleteAction(); + async function check(type: any, id: any) { + await action.execute({ type, savedObjectId: id }); + } + await expect(check('visualization', null)).rejects.toThrow(Error); + }); + + it('execute is successful if valid type and saved obj id', async () => { + const getLoaderSpy = jest.spyOn(services, 'getSavedAugmentVisLoader'); + const action = new SavedObjectDeleteAction(); + async function check(type: any, id: any) { + await action.execute({ type, savedObjectId: id }); + } + await expect(check('visualization', 'test-id')).resolves; + expect(getLoaderSpy).toHaveBeenCalledTimes(1); + }); + + it('Returns display name', async () => { + const action = new SavedObjectDeleteAction(); + expect(action.getDisplayName()).toBeDefined(); + }); + + it('Returns icon type', async () => { + const action = new SavedObjectDeleteAction(); + expect(action.getIconType()).toBeDefined(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/actions/saved_object_delete_action.ts b/src/plugins/vis_augmenter/public/actions/saved_object_delete_action.ts new file mode 100644 index 000000000000..5d031359a8d1 --- /dev/null +++ b/src/plugins/vis_augmenter/public/actions/saved_object_delete_action.ts @@ -0,0 +1,63 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isEmpty } from 'lodash'; +import { i18n } from '@osd/i18n'; +import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; +import { Action, IncompatibleActionError } from '../../../ui_actions/public'; +import { getAugmentVisSavedObjs } from '../utils'; +import { getSavedAugmentVisLoader } from '../services'; +import { SavedObjectDeleteContext } from '../ui_actions_bootstrap'; + +export const SAVED_OBJECT_DELETE_ACTION = 'SAVED_OBJECT_DELETE_ACTION'; + +export class SavedObjectDeleteAction implements Action { + public readonly type = SAVED_OBJECT_DELETE_ACTION; + public readonly id = SAVED_OBJECT_DELETE_ACTION; + public order = 1; + + public getIconType(): EuiIconType { + return `trash`; + } + + public getDisplayName() { + return i18n.translate('dashboard.actions.deleteSavedObject.name', { + defaultMessage: 'Clean up augment-vis saved objects associated to a deleted vis', + }); + } + + public async isCompatible({ type, savedObjectId }: SavedObjectDeleteContext) { + return type === 'visualization' && !!savedObjectId; + } + + /** + * If deletion of a vis saved object has been triggered, we want to clean up + * any augment-vis saved objects that have a reference to this vis since it + * is now stale. + * TODO: this should be automatically handled by the saved objects plugin, instead + * of this specific scenario in the vis_augmenter plugin. Tracking issue: + * https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4499 + */ + public async execute({ type, savedObjectId }: SavedObjectDeleteContext) { + if (!(await this.isCompatible({ type, savedObjectId }))) { + throw new IncompatibleActionError(); + } + + try { + const loader = getSavedAugmentVisLoader(); + const augmentVisObjs = await getAugmentVisSavedObjs(savedObjectId, loader); + const augmentVisIdsToDelete = augmentVisObjs.map( + (augmentVisObj) => augmentVisObj.id as string + ); + + if (!isEmpty(augmentVisIdsToDelete)) loader.delete(augmentVisIdsToDelete); + // silently fail. this is because this is doing extra cleanup on objects unrelated + // to the user flow so we dont want to add confusing errors on UI. + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } + } +} diff --git a/src/plugins/vis_augmenter/public/constants.ts b/src/plugins/vis_augmenter/public/constants.ts new file mode 100644 index 000000000000..9d422cf743a5 --- /dev/null +++ b/src/plugins/vis_augmenter/public/constants.ts @@ -0,0 +1,13 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const VIS_LAYER_COLUMN_TYPE = 'vis_layer'; +export const EVENT_COLOR = '#D36086'; // This is the value of ouiColorVis2 - we need the raw value so that vega can understand it +export const HOVER_PARAM = 'HOVER'; +export const EVENT_MARK_SIZE = 40; +export const EVENT_MARK_SIZE_ENLARGED = 80; +export const EVENT_MARK_SHAPE = 'triangle-up'; +export const EVENT_TIMELINE_HEIGHT = 25; +export const EVENT_TOOLTIP_CENTER_ON_MARK = 5; diff --git a/src/plugins/vis_augmenter/public/expressions/index.ts b/src/plugins/vis_augmenter/public/expressions/index.ts new file mode 100644 index 000000000000..9f269633f307 --- /dev/null +++ b/src/plugins/vis_augmenter/public/expressions/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './types'; diff --git a/src/plugins/vis_augmenter/public/expressions/types.ts b/src/plugins/vis_augmenter/public/expressions/types.ts new file mode 100644 index 000000000000..b907e570e108 --- /dev/null +++ b/src/plugins/vis_augmenter/public/expressions/types.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ExpressionTypeDefinition, ExpressionFunctionDefinition } from '../../../expressions'; +import { VisLayers, VisLayerTypes } from '../'; + +const name = 'vis_layers'; + +export interface ExprVisLayers { + type: typeof name; + layers: VisLayers; +} + +// Setting default empty arrays for null & undefined edge cases +export const visLayers: ExpressionTypeDefinition = { + name, + from: { + null: () => { + return { + type: name, + layers: [] as VisLayers, + } as ExprVisLayers; + }, + undefined: () => { + return { + type: name, + layers: [] as VisLayers, + } as ExprVisLayers; + }, + }, +}; + +export type VisLayerFunctionDefinition = ExpressionFunctionDefinition< + string, + ExprVisLayers, + any, + Promise +>; + +export interface VisLayerExpressionFn { + type: keyof typeof VisLayerTypes; + name: string; + // plugin expression fns can freely set custom arguments + args: { [key: string]: any }; +} diff --git a/src/plugins/vis_augmenter/public/index.ts b/src/plugins/vis_augmenter/public/index.ts new file mode 100644 index 000000000000..d5096b6faf1f --- /dev/null +++ b/src/plugins/vis_augmenter/public/index.ts @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PluginInitializerContext } from 'src/core/public'; +import { VisAugmenterPlugin, VisAugmenterSetup, VisAugmenterStart } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new VisAugmenterPlugin(initializerContext); +} +export { VisAugmenterSetup, VisAugmenterStart }; + +export { + VisLayer, + VisLayers, + VisLayerTypes, + VisLayerErrorTypes, + VisLayerError, + PluginResource, + PointInTimeEvent, + PointInTimeEventsVisLayer, + isPointInTimeEventsVisLayer, + isVisLayerWithError, + VisAugmenterEmbeddableConfig, + VisFlyoutContext, +} from './types'; + +export { AugmentVisContext } from './ui_actions_bootstrap'; + +export * from './expressions'; +export * from './utils'; +export * from './constants'; +export * from './vega'; +export * from './saved_augment_vis'; +export * from './test_constants'; +export * from './triggers'; +export * from './actions'; +export { fetchVisEmbeddable } from './view_events_flyout'; +export { setUISettings } from './services'; // Needed for plugin tests related to the CRUD saved object functions diff --git a/src/plugins/vis_augmenter/public/mocks.ts b/src/plugins/vis_augmenter/public/mocks.ts new file mode 100644 index 000000000000..33a6c3868e61 --- /dev/null +++ b/src/plugins/vis_augmenter/public/mocks.ts @@ -0,0 +1,228 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get } from 'lodash'; +import { VisualizeEmbeddable, Vis } from '../../visualizations/public'; +import { ErrorEmbeddable } from '../../embeddable/public'; +// eslint-disable-next-line @osd/eslint/no-restricted-paths +import { timefilterServiceMock } from '../../data/public/query/timefilter/timefilter_service.mock'; +import { EventVisEmbeddableItem } from './view_events_flyout'; +import { + VisLayer, + VisLayerTypes, + VisLayerErrorTypes, + PointInTimeEventsVisLayer, + PluginResource, + PointInTimeEvent, +} from './types'; +import { AggConfigs, AggTypesRegistryStart, IndexPattern } from '../../data/common'; +import { mockAggTypesRegistry } from '../../data/common/search/aggs/test_helpers'; + +export const VALID_CONFIG_STATES = [ + { + enabled: true, + type: 'max', + params: {}, + schema: 'metric', + }, + { + enabled: true, + type: 'date_histogram', + params: {}, + schema: 'segment', + }, +]; + +export const STUB_INDEX_PATTERN_WITH_FIELDS = { + id: '1234', + title: 'logstash-*', + fields: [ + { + name: 'response', + type: 'number', + esTypes: ['integer'], + aggregatable: true, + filterable: true, + searchable: true, + }, + ], +} as IndexPattern; + +export const TYPES_REGISTRY: AggTypesRegistryStart = mockAggTypesRegistry(); + +export const VALID_AGGS = new AggConfigs(STUB_INDEX_PATTERN_WITH_FIELDS, VALID_CONFIG_STATES, { + typesRegistry: TYPES_REGISTRY, +}); + +export const VALID_VIS = ({ + type: {}, + uiState: { + on: jest.fn(), + }, + params: { + type: 'line', + seriesParams: [ + { + type: 'line', + }, + ], + categoryAxes: [ + { + position: 'bottom', + }, + ], + }, + data: { + aggs: VALID_AGGS, + }, +} as unknown) as Vis; + +const SAVED_OBJ_ID = 'test-saved-obj-id'; +const VIS_TITLE = 'test-vis-title'; +const ORIGIN_PLUGIN = 'test-plugin'; +const PLUGIN_RESOURCE = { + type: 'test-type', + id: 'test-resource-id', + name: 'test-resource-name', + urlPath: 'test-url-path', +} as PluginResource; +const EVENT_COUNT = 3; +const ERROR_MESSAGE = 'test-error-message'; +const EVENT_TYPE = 'test-event-type'; + +export const createPluginResource = ( + type: string = PLUGIN_RESOURCE.type, + id: string = PLUGIN_RESOURCE.id, + name: string = PLUGIN_RESOURCE.name, + urlPath: string = PLUGIN_RESOURCE.urlPath +): PluginResource => { + return { + type, + id, + name, + urlPath, + }; +}; + +export const createMockErrorEmbeddable = (): ErrorEmbeddable => { + return new ErrorEmbeddable('Oh no something has gone wrong', { id: ' 404' }); +}; + +export const createMockVisEmbeddable = ( + savedObjectId: string = SAVED_OBJ_ID, + title: string = VIS_TITLE, + validVis: boolean = true +): VisualizeEmbeddable => { + const mockTimeFilterService = timefilterServiceMock.createStartContract(); + const mockTimeFilter = mockTimeFilterService.timefilter; + const mockVis = validVis + ? VALID_VIS + : (({ + type: {}, + data: {}, + uiState: { + on: jest.fn(), + }, + params: { + type: 'line', + seriesParams: [], + }, + } as unknown) as Vis); + const mockDeps = { + start: jest.fn(), + }; + const mockConfiguration = { + vis: mockVis, + editPath: 'test-edit-path', + editUrl: 'test-edit-url', + editable: true, + deps: mockDeps, + }; + const mockVisualizeInput = { id: 'test-id', savedObjectId }; + + const mockVisEmbeddable = new VisualizeEmbeddable( + mockTimeFilter, + mockConfiguration, + mockVisualizeInput + ); + mockVisEmbeddable.getTitle = () => title; + mockVisEmbeddable.visLayers = [createPointInTimeEventsVisLayer()]; + return mockVisEmbeddable; +}; + +export const createPointInTimeEventsVisLayer = ( + originPlugin: string = ORIGIN_PLUGIN, + pluginResource: PluginResource = PLUGIN_RESOURCE, + eventCount: number = EVENT_COUNT, + error: boolean = false, + errorMessage: string = ERROR_MESSAGE +): PointInTimeEventsVisLayer => { + const events = [] as PointInTimeEvent[]; + for (let i = 0; i < eventCount; i++) { + events.push({ + timestamp: i, + metadata: { + pluginResourceId: pluginResource.id, + }, + } as PointInTimeEvent); + } + return { + originPlugin, + type: VisLayerTypes.PointInTimeEvents, + pluginResource, + events, + pluginEventType: EVENT_TYPE, + error: error + ? { + type: VisLayerErrorTypes.FETCH_FAILURE, + message: errorMessage, + } + : undefined, + }; +}; + +export const createMockEventVisEmbeddableItem = ( + savedObjectId: string = SAVED_OBJ_ID, + title: string = VIS_TITLE, + originPlugin: string = ORIGIN_PLUGIN, + pluginResource: PluginResource = PLUGIN_RESOURCE, + eventCount: number = EVENT_COUNT +): EventVisEmbeddableItem => { + const visLayer = createPointInTimeEventsVisLayer(originPlugin, pluginResource, eventCount); + const embeddable = createMockVisEmbeddable(savedObjectId, title); + return { + visLayer, + embeddable, + }; +}; + +export const createVisLayer = ( + type: any, + error: boolean = false, + errorMessage: string = 'some-error-message', + resource?: { + type?: string; + id?: string; + name?: string; + urlPath?: string; + } +): VisLayer => { + return { + type, + originPlugin: 'test-plugin', + pluginResource: { + type: get(resource, 'type', 'test-resource-type'), + id: get(resource, 'id', 'test-resource-id'), + name: get(resource, 'name', 'test-resource-name'), + urlPath: get(resource, 'urlPath', 'test-resource-url-path'), + }, + error: error + ? { + type: VisLayerErrorTypes.FETCH_FAILURE, + message: errorMessage, + } + : undefined, + }; +}; diff --git a/src/plugins/vis_augmenter/public/plugin.ts b/src/plugins/vis_augmenter/public/plugin.ts new file mode 100644 index 000000000000..9760bfd75b2d --- /dev/null +++ b/src/plugins/vis_augmenter/public/plugin.ts @@ -0,0 +1,85 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ExpressionsSetup } from '../../expressions/public'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; +import { visLayers } from './expressions'; +import { setSavedAugmentVisLoader, setUISettings } from './services'; +import { createSavedAugmentVisLoader, SavedAugmentVisLoader } from './saved_augment_vis'; +import { UiActionsStart } from '../../ui_actions/public'; +import { + setUiActions, + setEmbeddable, + setQueryService, + setVisualizations, + setCore, +} from './services'; +import { EmbeddableStart } from '../../embeddable/public'; +import { DataPublicPluginStart } from '../../data/public'; +import { VisualizationsStart } from '../../visualizations/public'; +import { VIEW_EVENTS_FLYOUT_STATE, setFlyoutState } from './view_events_flyout'; +import { bootstrapUiActions } from './ui_actions_bootstrap'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VisAugmenterSetup {} + +export interface VisAugmenterStart { + savedAugmentVisLoader: SavedAugmentVisLoader; +} + +export interface VisAugmenterSetupDeps { + expressions: ExpressionsSetup; +} + +export interface VisAugmenterStartDeps { + uiActions: UiActionsStart; + embeddable: EmbeddableStart; + data: DataPublicPluginStart; + visualizations: VisualizationsStart; +} + +export class VisAugmenterPlugin + implements + Plugin { + constructor(initializerContext: PluginInitializerContext) {} + + public setup( + core: CoreSetup, + { expressions }: VisAugmenterSetupDeps + ): VisAugmenterSetup { + expressions.registerType(visLayers); + setUISettings(core.uiSettings); + + return {}; + } + + public start( + core: CoreStart, + { uiActions, embeddable, data, visualizations }: VisAugmenterStartDeps + ): VisAugmenterStart { + setUiActions(uiActions); + setEmbeddable(embeddable); + setQueryService(data.query); + setVisualizations(visualizations); + setCore(core); + setFlyoutState(VIEW_EVENTS_FLYOUT_STATE.CLOSED); + + const savedAugmentVisLoader = createSavedAugmentVisLoader({ + savedObjectsClient: core.savedObjects.client, + indexPatterns: data.indexPatterns, + search: data.search, + chrome: core.chrome, + overlays: core.overlays, + }); + setSavedAugmentVisLoader(savedAugmentVisLoader); + + // sets up the context mappings and registers any triggers/actions for the plugin + bootstrapUiActions(uiActions); + + return { savedAugmentVisLoader }; + } + + public stop() {} +} diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/_saved_augment_vis.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/_saved_augment_vis.ts new file mode 100644 index 000000000000..d40382b3a104 --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/_saved_augment_vis.ts @@ -0,0 +1,64 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @name SavedAugmentVis + * + * @extends SavedObject. + */ +import { get } from 'lodash'; +import { + createSavedObjectClass, + SavedObject, + SavedObjectOpenSearchDashboardsServices, +} from '../../../saved_objects/public'; +import { extractReferences, injectReferences } from './saved_augment_vis_references'; +import { AugmentVisSavedObjectAttributes } from '../../common'; + +const name = 'augment-vis'; + +export function createSavedAugmentVisClass(services: SavedObjectOpenSearchDashboardsServices) { + const SavedObjectClass = createSavedObjectClass(services); + + class SavedAugmentVis extends SavedObjectClass { + public static type: string = name; + public static mapping: Record = { + title: 'text', + description: 'text', + originPlugin: 'text', + pluginResource: 'object', + visLayerExpressionFn: 'object', + visId: 'keyword,', + version: 'integer', + }; + + constructor(opts: Record | string = {}) { + // The default delete() fn from the saved object loader will only + // pass a string ID. To handle that case here, we embed it within + // an opts object. + if (typeof opts !== 'object') { + opts = { id: opts }; + } + super({ + type: SavedAugmentVis.type, + mapping: SavedAugmentVis.mapping, + extractReferences, + injectReferences, + id: (opts.id as string) || '', + defaults: { + description: get(opts, 'description', ''), + originPlugin: get(opts, 'originPlugin', ''), + pluginResource: get(opts, 'pluginResource', {}), + visId: get(opts, 'visId', ''), + visLayerExpressionFn: get(opts, 'visLayerExpressionFn', {}), + version: 1, + }, + }); + this.showInRecentlyAccessed = false; + } + } + + return SavedAugmentVis as new (opts: AugmentVisSavedObjectAttributes) => SavedObject; +} diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/index.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/index.ts new file mode 100644 index 000000000000..ce1680204953 --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './saved_augment_vis'; +export * from './utils'; +export * from './types'; diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts new file mode 100644 index 000000000000..99975a54039b --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts @@ -0,0 +1,252 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { VisLayerTypes } from '../types'; +import { VisLayerExpressionFn } from '../expressions'; +import { + createSavedAugmentVisLoader, + SavedObjectOpenSearchDashboardsServicesWithAugmentVis, +} from './saved_augment_vis'; +import { generateAugmentVisSavedObject, getMockAugmentVisSavedObjectClient } from './utils'; +import { uiSettingsServiceMock } from '../../../../core/public/mocks'; +import { setUISettings } from '../services'; +import { PLUGIN_AUGMENTATION_ENABLE_SETTING } from '../../common/constants'; +import { ISavedPluginResource } from './types'; + +const uiSettingsMock = uiSettingsServiceMock.createStartContract(); +setUISettings(uiSettingsMock); + +describe('SavedObjectLoaderAugmentVis', () => { + uiSettingsMock.get.mockImplementation((key: string) => { + return key === PLUGIN_AUGMENTATION_ENABLE_SETTING; + }); + + const fn = { + type: VisLayerTypes.PointInTimeEvents, + name: 'test-fn', + args: { + testArg: 'test-value', + }, + } as VisLayerExpressionFn; + const originPlugin = 'test-plugin'; + const pluginResource = { + type: 'test-plugin', + id: 'test-plugin-resource-id', + }; + const validObj1 = generateAugmentVisSavedObject( + 'valid-obj-id-1', + fn, + 'test-vis-id', + originPlugin, + pluginResource + ); + const validObj2 = generateAugmentVisSavedObject( + 'valid-obj-id-2', + fn, + 'test-vis-id', + originPlugin, + pluginResource + ); + const invalidFnTypeObj = generateAugmentVisSavedObject( + 'invalid-fn-obj-id-1', + { + ...fn, + // @ts-ignore + type: 'invalid-type', + }, + 'test-vis-id', + originPlugin, + pluginResource + ); + + const missingFnObj = generateAugmentVisSavedObject( + 'missing-fn-obj-id-1', + {} as VisLayerExpressionFn, + 'test-vis-id', + originPlugin, + pluginResource + ); + + const missingOriginPluginObj = generateAugmentVisSavedObject( + 'missing-origin-plugin-obj-id-1', + fn, + 'test-vis-id', + // @ts-ignore + undefined, + pluginResource + ); + + const missingPluginResourceTypeObj = generateAugmentVisSavedObject( + 'missing-plugin-resource-type-obj-id-1', + fn, + 'test-vis-id', + // @ts-ignore + originPlugin, + { + id: pluginResource.id, + } as ISavedPluginResource + ); + + const missingPluginResourceIdObj = generateAugmentVisSavedObject( + 'missing-plugin-resource-id-obj-id-1', + fn, + 'test-vis-id', + // @ts-ignore + originPlugin, + { + type: pluginResource.type, + } as ISavedPluginResource + ); + + it('find returns single saved obj', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([validObj1]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.find(); + expect(resp.hits.length).toEqual(1); + expect(resp.hits[0].id).toEqual('valid-obj-id-1'); + expect(resp.hits[0].error).toEqual(undefined); + }); + + it('find returns multiple saved objs', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([validObj1, validObj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.find(); + expect(resp.hits.length).toEqual(2); + expect(resp.hits[0].id).toEqual('valid-obj-id-1'); + expect(resp.hits[1].id).toEqual('valid-obj-id-2'); + expect(resp.hits[0].error).toEqual(undefined); + expect(resp.hits[1].error).toEqual(undefined); + }); + + it('find returns empty response', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.find(); + expect(resp.hits.length).toEqual(0); + }); + + it('find does not return objs with errors', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([invalidFnTypeObj]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.find(); + expect(resp.hits.length).toEqual(0); + }); + + it('findAll returns obj with invalid VisLayer fn', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([invalidFnTypeObj]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.findAll(); + expect(resp.hits.length).toEqual(1); + expect(resp.hits[0].id).toEqual('invalid-fn-obj-id-1'); + expect(resp.hits[0].error).toEqual('Unknown VisLayer expression function type'); + }); + + it('findAll returns obj with missing VisLayer fn', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([missingFnObj]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.findAll(); + expect(resp.hits.length).toEqual(1); + expect(resp.hits[0].id).toEqual('missing-fn-obj-id-1'); + expect(resp.hits[0].error).toEqual( + 'visLayerExpressionFn is missing in augment-vis saved object' + ); + }); + + it('findAll returns obj with missing reference', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([validObj1], false), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.findAll(); + expect(resp.hits.length).toEqual(1); + expect(resp.hits[0].id).toEqual('valid-obj-id-1'); + expect(resp.hits[0].error).toEqual('visReference is missing in augment-vis saved object'); + }); + + it('findAll returns obj with missing originPlugin', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([missingOriginPluginObj]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.findAll(); + expect(resp.hits.length).toEqual(1); + expect(resp.hits[0].id).toEqual('missing-origin-plugin-obj-id-1'); + expect(resp.hits[0].error).toEqual('originPlugin is missing in augment-vis saved object'); + }); + + it('findAll returns obj with missing plugin resource type', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([missingPluginResourceTypeObj]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.findAll(); + expect(resp.hits.length).toEqual(1); + expect(resp.hits[0].id).toEqual('missing-plugin-resource-type-obj-id-1'); + expect(resp.hits[0].error).toEqual( + 'pluginResource.type is missing in augment-vis saved object' + ); + }); + + it('findAll returns obj with missing plugin resource id', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([missingPluginResourceIdObj]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + const resp = await loader.findAll(); + expect(resp.hits.length).toEqual(1); + expect(resp.hits[0].id).toEqual('missing-plugin-resource-id-obj-id-1'); + expect(resp.hits[0].error).toEqual('pluginResource.id is missing in augment-vis saved object'); + }); + + it('find returns exception due to setting being disabled', async () => { + uiSettingsMock.get.mockImplementation((key: string) => { + return key !== PLUGIN_AUGMENTATION_ENABLE_SETTING; + }); + const loader = createSavedAugmentVisLoader(({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([]), + } as unknown) as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + try { + await loader.find(); + } catch (e) { + expect(e.message).toBe( + 'Visualization augmentation is disabled, please enable visualization:enablePluginAugmentation.' + ); + } + }); + + it('findAll returns exception due to setting being disabled', async () => { + uiSettingsMock.get.mockImplementation((key: string) => { + return key !== PLUGIN_AUGMENTATION_ENABLE_SETTING; + }); + const loader = createSavedAugmentVisLoader(({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([]), + } as unknown) as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + try { + await loader.findAll(); + } catch (e) { + expect(e.message).toBe( + 'Visualization augmentation is disabled, please enable visualization:enablePluginAugmentation.' + ); + } + }); + + it('get returns exception due to setting being disabled', async () => { + uiSettingsMock.get.mockImplementation((key: string) => { + return key !== PLUGIN_AUGMENTATION_ENABLE_SETTING; + }); + const loader = createSavedAugmentVisLoader(({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([]), + } as unknown) as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + try { + await loader.get(); + } catch (e) { + expect(e.message).toBe( + 'Visualization augmentation is disabled, please enable visualization:enablePluginAugmentation.' + ); + } + }); +}); diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts new file mode 100644 index 000000000000..ff3769b6190d --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts @@ -0,0 +1,129 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get, isEmpty } from 'lodash'; +import { IUiSettingsClient, SavedObjectsFindOptions } from 'opensearch-dashboards/public'; +import { + SavedObjectLoader, + SavedObjectOpenSearchDashboardsServices, +} from '../../../saved_objects/public'; +import { createSavedAugmentVisClass } from './_saved_augment_vis'; +import { VisLayerTypes } from '../types'; +import { getUISettings } from '../services'; +import { AugmentVisSavedObjectAttributes, PLUGIN_AUGMENTATION_ENABLE_SETTING } from '../../common'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface SavedObjectOpenSearchDashboardsServicesWithAugmentVis + extends SavedObjectOpenSearchDashboardsServices {} +export type SavedAugmentVisLoader = ReturnType; + +export class SavedObjectLoaderAugmentVis extends SavedObjectLoader { + private readonly config: IUiSettingsClient = getUISettings(); + + mapHitSource = (source: AugmentVisSavedObjectAttributes, id: string) => { + source.id = id; + source.visId = get(source, 'visReference.id', '') as string; + + if (isEmpty(source.visReference)) { + source.error = 'visReference is missing in augment-vis saved object'; + return source; + } + if (isEmpty(source.visLayerExpressionFn)) { + source.error = 'visLayerExpressionFn is missing in augment-vis saved object'; + return source; + } + if (!((get(source, 'visLayerExpressionFn.type', '') as string) in VisLayerTypes)) { + source.error = 'Unknown VisLayer expression function type'; + return source; + } + if (get(source, 'originPlugin', undefined) === undefined) { + source.error = 'originPlugin is missing in augment-vis saved object'; + return source; + } + if (get(source, 'pluginResource.type', undefined) === undefined) { + source.error = 'pluginResource.type is missing in augment-vis saved object'; + return source; + } + if (get(source, 'pluginResource.id', undefined) === undefined) { + source.error = 'pluginResource.id is missing in augment-vis saved object'; + return source; + } + return source; + }; + + /** + * Updates hit.attributes to contain an id related to the referenced visualization + * (visId) and returns the updated attributes object. + * @param hit + * @returns {hit.attributes} The modified hit.attributes object, with an id and url field. + */ + mapSavedObjectApiHits(hit: { + references: any[]; + attributes: AugmentVisSavedObjectAttributes; + id: string; + }) { + // For now we are assuming only one vis reference per saved object. + // If we change to multiple, we will need to dynamically handle that + const visReference = hit.references[0]; + return this.mapHitSource({ ...hit.attributes, visReference }, hit.id); + } + + /** + * Retrieve a saved object by id or create new one. + * Returns a promise that completes when the object finishes + * initializing. Throws exception when the setting is set to false. + * @param opts + * @returns {Promise} + */ + get(opts?: Record | string) { + this.isAugmentationEnabled(); + return super.get(opts); + } + + /** + * TODO: Rather than use a hardcoded limit, implement pagination. See + * https://github.com/elastic/kibana/issues/8044 for reference. + * + * @param search + * @param size + * @param fields + * @param hasReference Optional field to specify a reference + * @param searchFields Optional field to specify the search fields in the query + * @returns {Promise} + */ + findAll( + search: string = '', + size: number = 100, + fields?: string[], + hasReference?: SavedObjectsFindOptions['hasReference'], + searchFields?: string[] + ) { + this.isAugmentationEnabled(); + return super.findAll(search, size, fields, hasReference, searchFields); + } + + find(search: string = '', size: number = 100) { + this.isAugmentationEnabled(); + return super.find(search, size); + } + + private isAugmentationEnabled() { + const isAugmentationEnabled = this.config.get(PLUGIN_AUGMENTATION_ENABLE_SETTING, true); + if (!isAugmentationEnabled) { + throw new Error( + 'Visualization augmentation is disabled, please enable visualization:enablePluginAugmentation.' + ); + } + } +} + +export function createSavedAugmentVisLoader( + services: SavedObjectOpenSearchDashboardsServicesWithAugmentVis +) { + const { savedObjectsClient } = services; + + const SavedAugmentVis = createSavedAugmentVisClass(services); + return new SavedObjectLoaderAugmentVis(SavedAugmentVis, savedObjectsClient); +} diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts new file mode 100644 index 000000000000..dd7aef79d9ad --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts @@ -0,0 +1,114 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + extractReferences, + injectReferences, + VIS_REFERENCE_NAME, +} from './saved_augment_vis_references'; +import { AugmentVisSavedObject } from './types'; + +describe('extractReferences()', () => { + test('extracts nothing if visId is null', () => { + const doc = { + id: '1', + attributes: { + foo: true, + }, + references: [], + }; + const updatedDoc = extractReferences(doc); + expect(updatedDoc).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "foo": true, + }, + "references": Array [], + } + `); + }); + + test('extracts references from visId', () => { + const doc = { + id: '1', + attributes: { + foo: true, + visId: 'test-id', + }, + references: [], + }; + const updatedDoc = extractReferences(doc); + expect(updatedDoc).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "foo": true, + "visName": "visualization_0", + }, + "references": Array [ + Object { + "id": "test-id", + "name": "visualization_0", + "type": "visualization", + }, + ], + } + `); + }); +}); + +describe('injectReferences()', () => { + test('injects nothing when visName is null', () => { + const context = ({ + id: '1', + pluginResourceId: 'test-resource-id', + visLayerExpressionFn: 'test-fn', + } as unknown) as AugmentVisSavedObject; + injectReferences(context, []); + expect(context).toMatchInlineSnapshot(` + Object { + "id": "1", + "pluginResourceId": "test-resource-id", + "visLayerExpressionFn": "test-fn", + } + `); + }); + + test('injects references into context', () => { + const context = ({ + id: '1', + pluginResourceId: 'test-resource-id', + visLayerExpressionFn: 'test-fn', + visName: VIS_REFERENCE_NAME, + } as unknown) as AugmentVisSavedObject; + const references = [ + { + name: VIS_REFERENCE_NAME, + type: 'visualization', + id: 'test-id', + }, + ]; + injectReferences(context, references); + expect(context).toMatchInlineSnapshot(` + Object { + "id": "1", + "pluginResourceId": "test-resource-id", + "visId": "test-id", + "visLayerExpressionFn": "test-fn", + } + `); + }); + + test(`fails when it can't find the saved object reference in the array`, () => { + const context = ({ + id: '1', + pluginResourceId: 'test-resource-id', + visLayerExpressionFn: 'test-fn', + visName: VIS_REFERENCE_NAME, + } as unknown) as AugmentVisSavedObject; + expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot( + `"Could not find visualization reference \\"${VIS_REFERENCE_NAME}\\""` + ); + }); +}); diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.ts new file mode 100644 index 000000000000..7a915f93745e --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.ts @@ -0,0 +1,75 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectAttributes, SavedObjectReference } from '../../../../core/public'; +import { AugmentVisSavedObjectAttributes } from '../../common'; +import { AugmentVisSavedObject } from './types'; + +/** + * Note that references aren't stored in the object's client-side interface (AugmentVisSavedObject). + * Rather, just the ID/type is. The concept of references is a server-side definition used to define + * relationships between saved objects. They are visible in the saved objs management page or + * when making direct saved obj API calls. + * + * So, we need helper fns to construct & deconstruct references when creating and reading the + * indexed/stored saved objects, respectively. + */ + +/** + * Using a constant value for the visualization name to easily extact/inject + * the reference. Setting as "_0" which could be expanded and incremented upon + * in the future if we decide to persist multiple visualizations per + * AugmentVisSavedObject. + */ +export const VIS_REFERENCE_NAME = 'visualization_0'; + +/** + * Used during creation. Converting from AugmentVisSavedObject to the actual indexed saved object + * with references. + */ +export function extractReferences({ + attributes, + references = [], +}: { + attributes: SavedObjectAttributes; + references: SavedObjectReference[]; +}) { + const updatedAttributes = { ...attributes } as AugmentVisSavedObjectAttributes; + const updatedReferences = [...references]; + + // Extract saved object + if (updatedAttributes.visId) { + updatedReferences.push({ + name: VIS_REFERENCE_NAME, + type: 'visualization', + id: String(updatedAttributes.visId), + }); + delete updatedAttributes.visId; + + updatedAttributes.visName = VIS_REFERENCE_NAME; + } + return { + references: updatedReferences, + attributes: updatedAttributes, + }; +} + +/** + * Used during reading. Converting from the indexed saved object with references + * to a AugmentVisSavedObject + */ +export function injectReferences( + savedObject: AugmentVisSavedObject, + references: SavedObjectReference[] +) { + if (savedObject.visName) { + const visReference = references.find((reference) => reference.name === savedObject.visName); + if (!visReference) { + throw new Error(`Could not find visualization reference "${savedObject.visName}"`); + } + savedObject.visId = visReference.id; + delete savedObject.visName; + } +} diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/types.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/types.ts new file mode 100644 index 000000000000..c2e5b8b19008 --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/types.ts @@ -0,0 +1,26 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObject } from '../../../saved_objects/public'; +import { VisLayerExpressionFn } from '../expressions'; + +export interface ISavedPluginResource { + type: string; + id: string; +} + +export interface ISavedAugmentVis { + id?: string; + title: string; + description?: string; + originPlugin: string; + pluginResource: ISavedPluginResource; + visName?: string; + visId?: string; + visLayerExpressionFn: VisLayerExpressionFn; + version?: number; +} + +export interface AugmentVisSavedObject extends SavedObject, ISavedAugmentVis {} diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/utils/helpers.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/helpers.ts new file mode 100644 index 000000000000..36fd15cefa06 --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/helpers.ts @@ -0,0 +1,56 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get } from 'lodash'; +import { ISavedAugmentVis } from '../types'; +import { + PLUGIN_AUGMENTATION_ENABLE_SETTING, + PLUGIN_AUGMENTATION_MAX_OBJECTS_SETTING, +} from '../../../common/constants'; +import { SavedAugmentVisLoader } from '../saved_augment_vis'; +import { getSavedAugmentVisLoader, getUISettings } from '../../services'; +import { IUiSettingsClient } from '../../../../../core/public'; + +/** + * Create an augment vis saved object given an object that + * implements the ISavedAugmentVis interface + */ +export const createAugmentVisSavedObject = async ( + AugmentVis: ISavedAugmentVis, + savedObjLoader?: SavedAugmentVisLoader, + uiSettings?: IUiSettingsClient +): Promise => { + // Using optional services provided, or the built-in services from this plugin + const loader = savedObjLoader !== undefined ? savedObjLoader : getSavedAugmentVisLoader(); + const config = uiSettings !== undefined ? uiSettings : getUISettings(); + const isAugmentationEnabled = config.get(PLUGIN_AUGMENTATION_ENABLE_SETTING); + if (!isAugmentationEnabled) { + throw new Error( + 'Visualization augmentation is disabled, please enable visualization:enablePluginAugmentation.' + ); + } + const maxAssociatedCount = config.get(PLUGIN_AUGMENTATION_MAX_OBJECTS_SETTING); + + await loader + .findAll('', 100, [], { + type: 'visualization', + id: AugmentVis.visId as string, + }) + .then(async (resp) => { + if (resp !== undefined) { + const savedObjectsForThisVisualization = get(resp, 'hits', []); + + if (maxAssociatedCount <= savedObjectsForThisVisualization.length) { + throw new Error( + `Cannot associate the plugin resource to the visualization due to the limit of the max + amount of associated plugin resources (${maxAssociatedCount}) with + ${savedObjectsForThisVisualization.length} associated to the visualization` + ); + } + } + }); + + return await loader.get((AugmentVis as any) as Record); +}; diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/utils/index.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/index.ts new file mode 100644 index 000000000000..aa4d6dbf3e35 --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './helpers'; +export * from './test_helpers'; diff --git a/src/plugins/vis_augmenter/public/saved_augment_vis/utils/test_helpers.ts b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/test_helpers.ts new file mode 100644 index 000000000000..c162fd3e0a6c --- /dev/null +++ b/src/plugins/vis_augmenter/public/saved_augment_vis/utils/test_helpers.ts @@ -0,0 +1,65 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { cloneDeep } from 'lodash'; +import { VisLayerExpressionFn, ISavedAugmentVis, ISavedPluginResource } from '../../'; +import { VIS_REFERENCE_NAME } from '../saved_augment_vis_references'; + +const title = 'test-title'; +const version = 1; + +export const generateAugmentVisSavedObject = ( + idArg: string, + exprFnArg: VisLayerExpressionFn, + visIdArg: string, + originPluginArg: string, + pluginResourceArg: ISavedPluginResource +) => { + return { + id: idArg, + title, + originPlugin: originPluginArg, + pluginResource: pluginResourceArg, + visLayerExpressionFn: exprFnArg, + VIS_REFERENCE_NAME, + visId: visIdArg, + version, + } as ISavedAugmentVis; +}; + +export const getMockAugmentVisSavedObjectClient = ( + augmentVisSavedObjs: ISavedAugmentVis[], + keepReferences: boolean = true +): any => { + const savedObjs = (augmentVisSavedObjs = cloneDeep(augmentVisSavedObjs)); + + const client = { + find: jest.fn(() => + Promise.resolve({ + total: savedObjs.length, + savedObjects: savedObjs.map((savedObj) => { + const objVisId = savedObj.visId; + const objId = savedObj.id; + delete savedObj.visId; + delete savedObj.id; + return { + id: objId, + attributes: savedObj as Record, + references: keepReferences + ? [ + { + name: savedObj.visName, + type: 'visualization', + id: objVisId, + }, + ] + : [], + }; + }), + }) + ), + } as any; + return client; +}; diff --git a/src/plugins/vis_augmenter/public/services.ts b/src/plugins/vis_augmenter/public/services.ts new file mode 100644 index 000000000000..1d7f3e2111db --- /dev/null +++ b/src/plugins/vis_augmenter/public/services.ts @@ -0,0 +1,45 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createGetterSetter } from '../../opensearch_dashboards_utils/public'; +import { IUiSettingsClient } from '../../../core/public'; +import { SavedObjectLoaderAugmentVis } from './saved_augment_vis'; +import { EmbeddableStart } from '../../embeddable/public'; +import { UiActionsStart } from '../../ui_actions/public'; +import { DataPublicPluginStart } from '../../../plugins/data/public'; +import { VisualizationsStart } from '../../visualizations/public'; +import { CoreStart } from '../../../core/public'; + +export const [getSavedAugmentVisLoader, setSavedAugmentVisLoader] = createGetterSetter< + SavedObjectLoaderAugmentVis +>('savedAugmentVisLoader'); + +export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); + +export const [getUiActions, setUiActions] = createGetterSetter('UIActions'); + +export const [getEmbeddable, setEmbeddable] = createGetterSetter('embeddable'); + +export const [getQueryService, setQueryService] = createGetterSetter< + DataPublicPluginStart['query'] +>('Query'); + +export const [getVisualizations, setVisualizations] = createGetterSetter( + 'visualizations' +); + +export const [getCore, setCore] = createGetterSetter('Core'); + +// This is primarily used for mocking this module and each of its fns in tests. +// eslint-disable-next-line import/no-default-export +export default { + getSavedAugmentVisLoader, + getUISettings, + getUiActions, + getEmbeddable, + getQueryService, + getVisualizations, + getCore, +}; diff --git a/src/plugins/vis_augmenter/public/test_constants.ts b/src/plugins/vis_augmenter/public/test_constants.ts new file mode 100644 index 000000000000..e792c100a55e --- /dev/null +++ b/src/plugins/vis_augmenter/public/test_constants.ts @@ -0,0 +1,740 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { OpenSearchDashboardsDatatable } from '../../expressions/public'; +import { VisAnnotationType } from './vega/constants'; +import { + VIS_LAYER_COLUMN_TYPE, + VisLayerTypes, + HOVER_PARAM, + EVENT_MARK_SIZE, + EVENT_MARK_SIZE_ENLARGED, + EVENT_COLOR, + EVENT_MARK_SHAPE, +} from './'; + +const TEST_X_AXIS_ID = 'test-x-axis-id'; +const TEST_X_AXIS_ID_DIRTY = 'test.x.axis.id'; +const TEST_VALUE_AXIS_ID = 'test-value-axis-id'; +const TEST_VALUE_AXIS_ID_DIRTY = 'test.value.axis.id'; +const TEST_X_AXIS_TITLE = 'time'; +const TEST_VALUE_AXIS_TITLE = 'avg value'; +const TEST_PLUGIN = 'test-plugin'; +const TEST_PLUGIN_EVENT_TYPE = 'test-plugin-event-type'; +const TEST_PLUGIN_EVENT_TYPE_2 = 'test-plugin-event-type-2'; +const TEST_PLUGIN_RESOURCE_TYPE = 'test-resource-type'; +const TEST_PLUGIN_RESOURCE_ID = 'test-resource-id'; +const TEST_PLUGIN_RESOURCE_ID_2 = 'test-resource-id-2'; +const TEST_PLUGIN_RESOURCE_NAME = 'test-resource-name'; +const TEST_PLUGIN_RESOURCE_NAME_2 = 'test-resource-name-2'; +const TEST_PLUGIN_RESOURCE_PATH = `${TEST_PLUGIN}/${TEST_PLUGIN_RESOURCE_TYPE}/${TEST_PLUGIN_RESOURCE_ID}`; +const TEST_PLUGIN_RESOURCE_PATH_2 = `${TEST_PLUGIN}/${TEST_PLUGIN_RESOURCE_TYPE}/${TEST_PLUGIN_RESOURCE_ID_2}`; + +const TEST_VALUES_SINGLE_ROW_NO_VIS_LAYERS = [{ [TEST_X_AXIS_ID]: 0, [TEST_VALUE_AXIS_ID]: 5 }]; + +const TEST_VALUES_SINGLE_ROW_SINGLE_VIS_LAYER = [ + { [TEST_X_AXIS_ID]: 0, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 3 }, +]; + +const TEST_VALUES_ONLY_VIS_LAYERS = [ + { [TEST_X_AXIS_ID]: 0, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 2 }, + { [TEST_X_AXIS_ID]: 10, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 15, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 20, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 25, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 30, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 35, [TEST_PLUGIN_EVENT_TYPE]: 1 }, + { [TEST_X_AXIS_ID]: 40, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 45, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 50, [TEST_PLUGIN_EVENT_TYPE]: 0 }, +]; + +const TEST_VALUES_NO_VIS_LAYERS = [ + { [TEST_X_AXIS_ID]: 0, [TEST_VALUE_AXIS_ID]: 5 }, + { [TEST_X_AXIS_ID]: 5, [TEST_VALUE_AXIS_ID]: 10 }, + { [TEST_X_AXIS_ID]: 10, [TEST_VALUE_AXIS_ID]: 6 }, + { [TEST_X_AXIS_ID]: 15, [TEST_VALUE_AXIS_ID]: 4 }, + { [TEST_X_AXIS_ID]: 20, [TEST_VALUE_AXIS_ID]: 5 }, + { [TEST_X_AXIS_ID]: 25 }, + { [TEST_X_AXIS_ID]: 30 }, + { [TEST_X_AXIS_ID]: 35 }, + { [TEST_X_AXIS_ID]: 40 }, + { [TEST_X_AXIS_ID]: 45, [TEST_VALUE_AXIS_ID]: 3 }, + { [TEST_X_AXIS_ID]: 50, [TEST_VALUE_AXIS_ID]: 5 }, +]; + +const TEST_VALUES_SINGLE_VIS_LAYER_EMPTY = [ + { [TEST_X_AXIS_ID]: 0, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 5, [TEST_VALUE_AXIS_ID]: 10, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 10, [TEST_VALUE_AXIS_ID]: 6, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 15, [TEST_VALUE_AXIS_ID]: 4, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 20, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 25, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 30, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 35, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 40, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 45, [TEST_VALUE_AXIS_ID]: 3, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 50, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 0 }, +]; + +const TEST_VALUES_NO_VIS_LAYERS_DIRTY = [ + { [TEST_X_AXIS_ID_DIRTY]: 0, [TEST_VALUE_AXIS_ID_DIRTY]: 5 }, + { [TEST_X_AXIS_ID_DIRTY]: 5, [TEST_VALUE_AXIS_ID_DIRTY]: 10 }, + { [TEST_X_AXIS_ID_DIRTY]: 10, [TEST_VALUE_AXIS_ID_DIRTY]: 6 }, + { [TEST_X_AXIS_ID_DIRTY]: 15, [TEST_VALUE_AXIS_ID_DIRTY]: 4 }, + { [TEST_X_AXIS_ID_DIRTY]: 20, [TEST_VALUE_AXIS_ID_DIRTY]: 5 }, + { [TEST_X_AXIS_ID_DIRTY]: 25 }, + { [TEST_X_AXIS_ID_DIRTY]: 30 }, + { [TEST_X_AXIS_ID_DIRTY]: 35 }, + { [TEST_X_AXIS_ID_DIRTY]: 40 }, + { [TEST_X_AXIS_ID_DIRTY]: 45, [TEST_VALUE_AXIS_ID_DIRTY]: 3 }, + { [TEST_X_AXIS_ID_DIRTY]: 50, [TEST_VALUE_AXIS_ID_DIRTY]: 5 }, +]; + +const TEST_VALUES_SINGLE_VIS_LAYER = [ + { [TEST_X_AXIS_ID]: 0, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 5, [TEST_VALUE_AXIS_ID]: 10, [TEST_PLUGIN_EVENT_TYPE]: 2 }, + { [TEST_X_AXIS_ID]: 10, [TEST_VALUE_AXIS_ID]: 6, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 15, [TEST_VALUE_AXIS_ID]: 4, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 20, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 25, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 30, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 35, [TEST_PLUGIN_EVENT_TYPE]: 1 }, + { [TEST_X_AXIS_ID]: 40, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 45, [TEST_VALUE_AXIS_ID]: 3, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 50, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 0 }, +]; + +const TEST_VALUES_SINGLE_VIS_LAYER_ON_BOUNDS = [ + { [TEST_X_AXIS_ID]: 0, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 2 }, + { [TEST_X_AXIS_ID]: 5, [TEST_VALUE_AXIS_ID]: 10, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 10, [TEST_VALUE_AXIS_ID]: 6, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 15, [TEST_VALUE_AXIS_ID]: 4, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 20, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 25, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 30, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 35, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 40, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 45, [TEST_VALUE_AXIS_ID]: 3, [TEST_PLUGIN_EVENT_TYPE]: 0 }, + { [TEST_X_AXIS_ID]: 50, [TEST_VALUE_AXIS_ID]: 5, [TEST_PLUGIN_EVENT_TYPE]: 1 }, +]; + +const TEST_VALUES_MULTIPLE_VIS_LAYERS = [ + { + [TEST_X_AXIS_ID]: 0, + [TEST_VALUE_AXIS_ID]: 5, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 5, + [TEST_VALUE_AXIS_ID]: 10, + [TEST_PLUGIN_EVENT_TYPE]: 2, + [TEST_PLUGIN_EVENT_TYPE_2]: 1, + }, + { + [TEST_X_AXIS_ID]: 10, + [TEST_VALUE_AXIS_ID]: 6, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 15, + [TEST_VALUE_AXIS_ID]: 4, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 1, + }, + { + [TEST_X_AXIS_ID]: 20, + [TEST_VALUE_AXIS_ID]: 5, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { [TEST_X_AXIS_ID]: 25, [TEST_PLUGIN_EVENT_TYPE]: 0, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { [TEST_X_AXIS_ID]: 30, [TEST_PLUGIN_EVENT_TYPE]: 0, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { [TEST_X_AXIS_ID]: 35, [TEST_PLUGIN_EVENT_TYPE]: 1, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { [TEST_X_AXIS_ID]: 40, [TEST_PLUGIN_EVENT_TYPE]: 0, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { + [TEST_X_AXIS_ID]: 45, + [TEST_VALUE_AXIS_ID]: 3, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 50, + [TEST_VALUE_AXIS_ID]: 5, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 2, + }, +]; + +const TEST_VALUES_MULTIPLE_VIS_LAYERS_ONE_EMPTY = [ + { + [TEST_X_AXIS_ID]: 0, + [TEST_VALUE_AXIS_ID]: 5, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 5, + [TEST_VALUE_AXIS_ID]: 10, + [TEST_PLUGIN_EVENT_TYPE]: 2, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 10, + [TEST_VALUE_AXIS_ID]: 6, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 15, + [TEST_VALUE_AXIS_ID]: 4, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 20, + [TEST_VALUE_AXIS_ID]: 5, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { [TEST_X_AXIS_ID]: 25, [TEST_PLUGIN_EVENT_TYPE]: 0, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { [TEST_X_AXIS_ID]: 30, [TEST_PLUGIN_EVENT_TYPE]: 0, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { [TEST_X_AXIS_ID]: 35, [TEST_PLUGIN_EVENT_TYPE]: 1, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { [TEST_X_AXIS_ID]: 40, [TEST_PLUGIN_EVENT_TYPE]: 0, [TEST_PLUGIN_EVENT_TYPE_2]: 0 }, + { + [TEST_X_AXIS_ID]: 45, + [TEST_VALUE_AXIS_ID]: 3, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, + { + [TEST_X_AXIS_ID]: 50, + [TEST_VALUE_AXIS_ID]: 5, + [TEST_PLUGIN_EVENT_TYPE]: 0, + [TEST_PLUGIN_EVENT_TYPE_2]: 0, + }, +]; + +export const TEST_COLUMNS_NO_VIS_LAYERS = [ + { + id: TEST_X_AXIS_ID, + name: TEST_X_AXIS_TITLE, + }, + { + id: TEST_VALUE_AXIS_ID, + name: TEST_VALUE_AXIS_TITLE, + }, +]; + +export const TEST_COLUMNS_NO_VIS_LAYERS_DIRTY = [ + { + id: TEST_X_AXIS_ID_DIRTY, + name: TEST_X_AXIS_TITLE, + }, + { + id: TEST_VALUE_AXIS_ID_DIRTY, + name: TEST_VALUE_AXIS_TITLE, + }, +]; + +export const TEST_COLUMNS_SINGLE_VIS_LAYER = [ + ...TEST_COLUMNS_NO_VIS_LAYERS, + { + id: TEST_PLUGIN_EVENT_TYPE, + name: `${TEST_PLUGIN_EVENT_TYPE} count`, + meta: { + type: VIS_LAYER_COLUMN_TYPE, + }, + }, +]; + +export const TEST_COLUMNS_MULTIPLE_VIS_LAYERS = [ + ...TEST_COLUMNS_SINGLE_VIS_LAYER, + { + id: TEST_PLUGIN_EVENT_TYPE_2, + name: `${TEST_PLUGIN_EVENT_TYPE_2} count`, + meta: { + type: VIS_LAYER_COLUMN_TYPE, + }, + }, +]; + +export const TEST_DATATABLE_SINGLE_ROW_NO_VIS_LAYERS = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_NO_VIS_LAYERS, + rows: TEST_VALUES_SINGLE_ROW_NO_VIS_LAYERS, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_SINGLE_ROW_SINGLE_VIS_LAYER = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_SINGLE_VIS_LAYER, + rows: TEST_VALUES_SINGLE_ROW_SINGLE_VIS_LAYER, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_ONLY_VIS_LAYERS = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_SINGLE_VIS_LAYER, + rows: TEST_VALUES_ONLY_VIS_LAYERS, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_NO_VIS_LAYERS = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_NO_VIS_LAYERS, + rows: TEST_VALUES_NO_VIS_LAYERS, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_NO_VIS_LAYERS_DIRTY = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_NO_VIS_LAYERS_DIRTY, + rows: TEST_VALUES_NO_VIS_LAYERS_DIRTY, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_SINGLE_VIS_LAYER_EMPTY = { + ...TEST_DATATABLE_NO_VIS_LAYERS, + columns: TEST_COLUMNS_SINGLE_VIS_LAYER, + rows: TEST_VALUES_SINGLE_VIS_LAYER_EMPTY, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_SINGLE_VIS_LAYER = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_SINGLE_VIS_LAYER, + rows: TEST_VALUES_SINGLE_VIS_LAYER, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_SINGLE_VIS_LAYER_ON_BOUNDS = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_SINGLE_VIS_LAYER, + rows: TEST_VALUES_SINGLE_VIS_LAYER_ON_BOUNDS, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_MULTIPLE_VIS_LAYERS = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_MULTIPLE_VIS_LAYERS, + rows: TEST_VALUES_MULTIPLE_VIS_LAYERS, +} as OpenSearchDashboardsDatatable; + +export const TEST_DATATABLE_MULTIPLE_VIS_LAYERS_ONE_EMPTY = { + type: 'opensearch_dashboards_datatable', + columns: TEST_COLUMNS_MULTIPLE_VIS_LAYERS, + rows: TEST_VALUES_MULTIPLE_VIS_LAYERS_ONE_EMPTY, +} as OpenSearchDashboardsDatatable; + +const TEST_BASE_CONFIG = { + view: { stroke: null }, + concat: { spacing: 0 }, + legend: { orient: 'right' }, + kibana: { hideWarnings: true }, +}; + +const TEST_BASE_VIS_LAYER = { + mark: { type: 'line', interpolate: 'linear', strokeWidth: 2, point: true }, + encoding: { + x: { + axis: { title: TEST_X_AXIS_TITLE, grid: false }, + field: TEST_X_AXIS_ID, + type: 'temporal', + }, + y: { + axis: { + title: TEST_VALUE_AXIS_TITLE, + grid: '', + orient: 'left', + labels: true, + labelAngle: 0, + }, + field: TEST_VALUE_AXIS_ID, + type: 'quantitative', + }, + tooltip: [ + { field: TEST_X_AXIS_ID, type: 'temporal', title: TEST_VALUE_AXIS_TITLE }, + { field: TEST_VALUE_AXIS_ID, type: 'quantitative', title: TEST_VALUE_AXIS_TITLE }, + ], + color: { datum: TEST_VALUE_AXIS_TITLE }, + }, +}; + +export const TEST_SPEC_NO_VIS_LAYERS = { + $schema: 'https://vega.github.io/schema/vega-lite/v5.json', + data: { + values: TEST_VALUES_NO_VIS_LAYERS, + }, + config: TEST_BASE_CONFIG, + layer: [TEST_BASE_VIS_LAYER], +}; + +export const TEST_SPEC_SINGLE_VIS_LAYER = { + ...TEST_SPEC_NO_VIS_LAYERS, + data: { + ...TEST_SPEC_NO_VIS_LAYERS.data, + values: TEST_VALUES_SINGLE_VIS_LAYER, + }, +}; + +export const TEST_SPEC_MULTIPLE_VIS_LAYERS = { + ...TEST_SPEC_NO_VIS_LAYERS, + data: { + ...TEST_SPEC_NO_VIS_LAYERS.data, + values: TEST_VALUES_MULTIPLE_VIS_LAYERS, + }, +}; + +export const TEST_DIMENSIONS = { + x: { + params: { + interval: 5, + bounds: { + min: 0, + max: 50, + }, + }, + label: TEST_X_AXIS_TITLE, + }, +}; + +export const TEST_DIMENSIONS_SINGLE_ROW = { + x: { + params: { + interval: 5, + bounds: { + min: 0, + max: 0, + }, + }, + label: TEST_X_AXIS_TITLE, + }, +}; + +export const TEST_DIMENSIONS_INVALID_BOUNDS = { + x: { + params: { + interval: 5, + bounds: { + min: 50, + max: 0, + }, + }, + label: TEST_X_AXIS_TITLE, + }, +}; + +export const TEST_VIS_LAYERS_SINGLE = [ + { + originPlugin: TEST_PLUGIN, + type: VisLayerTypes.PointInTimeEvents, + pluginResource: { + type: TEST_PLUGIN_RESOURCE_TYPE, + id: TEST_PLUGIN_RESOURCE_ID, + name: TEST_PLUGIN_RESOURCE_NAME, + urlPath: TEST_PLUGIN_RESOURCE_PATH, + }, + pluginEventType: TEST_PLUGIN_EVENT_TYPE, + events: [ + { + timestamp: 4, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + { + timestamp: 6, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + { + timestamp: 35, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + ], + }, +]; + +export const TEST_VIS_LAYERS_SINGLE_INVALID_BOUNDS = [ + { + originPlugin: TEST_PLUGIN, + type: VisLayerTypes.PointInTimeEvents, + pluginResource: { + type: TEST_PLUGIN_RESOURCE_TYPE, + id: TEST_PLUGIN_RESOURCE_ID, + name: TEST_PLUGIN_RESOURCE_NAME, + urlPath: TEST_PLUGIN_RESOURCE_PATH, + }, + pluginEventType: TEST_PLUGIN_EVENT_TYPE, + events: [ + { + timestamp: -5, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + { + timestamp: -100, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + { + timestamp: 75, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + ], + }, +]; + +export const TEST_VIS_LAYERS_SINGLE_ON_BOUNDS = [ + { + originPlugin: TEST_PLUGIN, + type: VisLayerTypes.PointInTimeEvents, + pluginResource: { + type: TEST_PLUGIN_RESOURCE_TYPE, + id: TEST_PLUGIN_RESOURCE_ID, + name: TEST_PLUGIN_RESOURCE_NAME, + urlPath: TEST_PLUGIN_RESOURCE_PATH, + }, + pluginEventType: TEST_PLUGIN_EVENT_TYPE, + events: [ + { + timestamp: 0, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + { + timestamp: 2, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + { + timestamp: 55, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID, + }, + }, + ], + }, +]; + +export const TEST_VIS_LAYERS_MULTIPLE = [ + ...TEST_VIS_LAYERS_SINGLE, + { + originPlugin: TEST_PLUGIN, + type: VisLayerTypes.PointInTimeEvents, + pluginResource: { + type: TEST_PLUGIN_RESOURCE_TYPE, + id: TEST_PLUGIN_RESOURCE_ID_2, + name: TEST_PLUGIN_RESOURCE_NAME_2, + urlPath: TEST_PLUGIN_RESOURCE_PATH_2, + }, + pluginEventType: TEST_PLUGIN_EVENT_TYPE_2, + events: [ + { + timestamp: 5, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID_2, + }, + }, + { + timestamp: 15, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID_2, + }, + }, + { + timestamp: 49, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID_2, + }, + }, + { + timestamp: 50, + metadata: { + pluginResourceId: TEST_PLUGIN_RESOURCE_ID_2, + }, + }, + ], + }, +]; + +export const TEST_VIS_LAYERS_MULTIPLE_ONE_EMPTY = [ + ...TEST_VIS_LAYERS_SINGLE, + { + originPlugin: TEST_PLUGIN, + type: VisLayerTypes.PointInTimeEvents, + pluginResource: { + type: TEST_PLUGIN_RESOURCE_TYPE, + id: TEST_PLUGIN_RESOURCE_ID_2, + name: TEST_PLUGIN_RESOURCE_NAME_2, + urlPath: TEST_PLUGIN_RESOURCE_PATH_2, + }, + pluginEventType: TEST_PLUGIN_EVENT_TYPE_2, + events: [], + }, +]; + +const TEST_RULE_LAYER_SINGLE_VIS_LAYER = { + mark: { type: 'rule', color: EVENT_COLOR, opacity: 1 }, + transform: [{ filter: `datum['${TEST_PLUGIN_EVENT_TYPE}'] > 0` }], + encoding: { + x: { field: TEST_X_AXIS_ID, type: 'temporal' }, + opacity: { value: 0, condition: { empty: false, param: HOVER_PARAM, value: 1 } }, + }, +}; + +const TEST_RULE_LAYER_MULTIPLE_VIS_LAYERS = { + ...TEST_RULE_LAYER_SINGLE_VIS_LAYER, + transform: [ + { + filter: `datum['${TEST_PLUGIN_EVENT_TYPE}'] > 0 || datum['${TEST_PLUGIN_EVENT_TYPE_2}'] > 0`, + }, + ], +}; + +const TEST_EVENTS_LAYER_SINGLE_VIS_LAYER = { + height: 25, + mark: { + type: 'point', + shape: EVENT_MARK_SHAPE, + fill: EVENT_COLOR, + fillOpacity: 1, + stroke: EVENT_COLOR, + strokeOpacity: 1, + style: [`${VisAnnotationType.POINT_IN_TIME_ANNOTATION}`], + tooltip: true, + }, + transform: [ + { filter: `datum['${TEST_PLUGIN_EVENT_TYPE}'] > 0` }, + { calculate: `'${VisAnnotationType.POINT_IN_TIME_ANNOTATION}'`, as: 'annotationType' }, + ], + params: [{ name: HOVER_PARAM, select: { type: 'point', on: 'mouseover' } }], + encoding: { + x: { + axis: { + title: TEST_X_AXIS_TITLE, + grid: false, + ticks: true, + orient: 'bottom', + domain: true, + }, + field: TEST_X_AXIS_ID, + type: 'temporal', + scale: { + domain: [ + { + year: 2022, + month: 'December', + date: 1, + hours: 0, + minutes: 0, + seconds: 0, + milliseconds: 0, + }, + { + year: 2023, + month: 'March', + date: 2, + hours: 0, + minutes: 0, + seconds: 0, + milliseconds: 0, + }, + ], + }, + }, + size: { + condition: { empty: false, param: HOVER_PARAM, value: EVENT_MARK_SIZE_ENLARGED }, + value: EVENT_MARK_SIZE, + }, + tooltip: [{ field: TEST_PLUGIN_EVENT_TYPE }], + }, +}; + +const TEST_EVENTS_LAYER_MULTIPLE_VIS_LAYERS = { + ...TEST_EVENTS_LAYER_SINGLE_VIS_LAYER, + transform: [ + { + filter: `datum['${TEST_PLUGIN_EVENT_TYPE}'] > 0 || datum['${TEST_PLUGIN_EVENT_TYPE_2}'] > 0`, + }, + { calculate: `'${VisAnnotationType.POINT_IN_TIME_ANNOTATION}'`, as: 'annotationType' }, + ], + encoding: { + ...TEST_EVENTS_LAYER_SINGLE_VIS_LAYER.encoding, + tooltip: [{ field: TEST_PLUGIN_EVENT_TYPE }, { field: TEST_PLUGIN_EVENT_TYPE_2 }], + }, +}; + +export const TEST_RESULT_SPEC_SINGLE_VIS_LAYER = { + $schema: 'https://vega.github.io/schema/vega-lite/v5.json', + data: { + values: TEST_VALUES_SINGLE_VIS_LAYER, + }, + config: TEST_BASE_CONFIG, + vconcat: [ + { + layer: [ + { + ...TEST_BASE_VIS_LAYER, + encoding: { + ...TEST_BASE_VIS_LAYER.encoding, + x: { + ...TEST_BASE_VIS_LAYER.encoding.x, + axis: { + title: null, + grid: false, + labels: false, + }, + }, + }, + }, + TEST_RULE_LAYER_SINGLE_VIS_LAYER, + ], + }, + TEST_EVENTS_LAYER_SINGLE_VIS_LAYER, + ], +}; + +export const TEST_RESULT_SPEC_SINGLE_VIS_LAYER_EMPTY = { + ...TEST_RESULT_SPEC_SINGLE_VIS_LAYER, + data: { + values: TEST_VALUES_NO_VIS_LAYERS, + }, +}; + +export const TEST_RESULT_SPEC_MULTIPLE_VIS_LAYERS = { + $schema: 'https://vega.github.io/schema/vega-lite/v5.json', + data: { + values: TEST_VALUES_MULTIPLE_VIS_LAYERS, + }, + config: TEST_BASE_CONFIG, + vconcat: [ + { + layer: [ + { + ...TEST_BASE_VIS_LAYER, + encoding: { + ...TEST_BASE_VIS_LAYER.encoding, + x: { + ...TEST_BASE_VIS_LAYER.encoding.x, + axis: { + title: null, + grid: false, + labels: false, + }, + }, + }, + }, + TEST_RULE_LAYER_MULTIPLE_VIS_LAYERS, + ], + }, + TEST_EVENTS_LAYER_MULTIPLE_VIS_LAYERS, + ], +}; diff --git a/src/plugins/vis_augmenter/public/triggers/index.ts b/src/plugins/vis_augmenter/public/triggers/index.ts new file mode 100644 index 000000000000..5b1833e38d62 --- /dev/null +++ b/src/plugins/vis_augmenter/public/triggers/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { + PLUGIN_RESOURCE_DELETE_TRIGGER, + pluginResourceDeleteTrigger, +} from './plugin_resource_delete_trigger'; diff --git a/src/plugins/vis_augmenter/public/triggers/plugin_resource_delete_trigger.ts b/src/plugins/vis_augmenter/public/triggers/plugin_resource_delete_trigger.ts new file mode 100644 index 000000000000..249bb61132eb --- /dev/null +++ b/src/plugins/vis_augmenter/public/triggers/plugin_resource_delete_trigger.ts @@ -0,0 +1,18 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { Trigger } from '../../../ui_actions/public'; + +export const PLUGIN_RESOURCE_DELETE_TRIGGER = 'PLUGIN_RESOURCE_DELETE_TRIGGER'; +export const pluginResourceDeleteTrigger: Trigger<'PLUGIN_RESOURCE_DELETE_TRIGGER'> = { + id: PLUGIN_RESOURCE_DELETE_TRIGGER, + title: i18n.translate('visAugmenter.triggers.pluginResourceDeleteTitle', { + defaultMessage: 'Plugin resource delete', + }), + description: i18n.translate('visAugmenter.triggers.pluginResourceDeleteDescription', { + defaultMessage: 'Delete augment-vis saved objs associated to the deleted plugin resource', + }), +}; diff --git a/src/plugins/vis_augmenter/public/types.test.ts b/src/plugins/vis_augmenter/public/types.test.ts new file mode 100644 index 000000000000..4bd4cb1221c3 --- /dev/null +++ b/src/plugins/vis_augmenter/public/types.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + VisLayerTypes, + isPointInTimeEventsVisLayer, + isValidVisLayer, + isVisLayerWithError, +} from './types'; +import { createVisLayer } from './mocks'; + +describe('isPointInTimeEventsVisLayer()', function () { + it('should return false if type does not match', function () { + const visLayer = createVisLayer('unknown-vis-layer-type'); + expect(isPointInTimeEventsVisLayer(visLayer)).toBe(false); + }); + + it('should return true if type matches', function () { + const visLayer = createVisLayer(VisLayerTypes.PointInTimeEvents); + expect(isPointInTimeEventsVisLayer(visLayer)).toBe(true); + }); +}); + +describe('isValidVisLayer()', function () { + it('should return false if no valid type', function () { + const visLayer = createVisLayer('unknown-vis-layer-type'); + expect(isValidVisLayer(visLayer)).toBe(false); + }); + + it('should return true if type matches', function () { + const visLayer = createVisLayer(VisLayerTypes.PointInTimeEvents); + expect(isValidVisLayer(visLayer)).toBe(true); + }); +}); + +describe('isVisLayerWithError()', function () { + it('should return false if no error', function () { + const visLayer = createVisLayer('unknown-vis-layer-type', false); + expect(isVisLayerWithError(visLayer)).toBe(false); + }); + + it('should return true if error', function () { + const visLayer = createVisLayer(VisLayerTypes.PointInTimeEvents, true); + expect(isVisLayerWithError(visLayer)).toBe(true); + }); +}); diff --git a/src/plugins/vis_augmenter/public/types.ts b/src/plugins/vis_augmenter/public/types.ts new file mode 100644 index 000000000000..e054ab008fe3 --- /dev/null +++ b/src/plugins/vis_augmenter/public/types.ts @@ -0,0 +1,97 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export enum VisLayerTypes { + PointInTimeEvents = 'PointInTimeEvents', +} + +export enum VisLayerErrorTypes { + PERMISSIONS_FAILURE = 'PERMISSIONS_FAILURE', + FETCH_FAILURE = 'FETCH_FAILURE', + RESOURCE_DELETED = 'RESOURCE_DELETED', +} + +export enum VisFlyoutContext { + BASE_VIS = 'BASE_VIS', + EVENT_VIS = 'EVENT_VIS', + TIMELINE_VIS = 'TIMELINE_VIS', +} + +export interface VisLayerError { + type: keyof typeof VisLayerErrorTypes; + message: string; +} + +export type PluginResourceType = string; + +export interface PluginResource { + type: PluginResourceType; + // Should match what is persisted in the plugin + id: string; + // Should match what is persisted in the plugin + name: string; + // Should be the full path to the resource details page + // in the respective plugin. Will be used in the hyperlinked + // name of the resource when viewed in the View Events flyout + urlPath: string; +} + +export interface VisLayer { + type: keyof typeof VisLayerTypes; + // A unique name for the plugin. Is used to partition data + // on the View Events flyout by plugin. + originPlugin: string; + // The specific plugin resource - e.g., an anomaly detector + pluginResource: PluginResource; + error?: VisLayerError; +} + +export type VisLayers = VisLayer[]; + +export interface EventMetadata { + pluginResourceId: string; +} + +export interface PointInTimeEvent { + timestamp: number; + metadata: EventMetadata; +} + +export interface PointInTimeEventsVisLayer extends VisLayer { + events: PointInTimeEvent[]; + // Should be the plugin-specific event name, such as 'Anomalies'. + // Will be visible in the tooltips when hovering over an event + // in a visualization. + pluginEventType: string; +} + +export const isPointInTimeEventsVisLayer = (obj: any) => { + return obj?.type === VisLayerTypes.PointInTimeEvents; +}; + +/** + * Used to determine if a given saved obj has a valid type and can + * be converted into a VisLayer + */ +export const isValidVisLayer = (obj: any) => { + return obj?.type in VisLayerTypes; +}; + +/** + * Used for checking if an existing VisLayer has a populated error field or not + */ +export const isVisLayerWithError = (visLayer: VisLayer): boolean => visLayer.error !== undefined; +// We need to have some extra config in order to render the charts correctly in different contexts. +// For example, we use the same base vis and modify it within the view events flyout to hide +// axes, only show events, only show timeline, add custom padding, etc. +// So, we abstract these concepts out and let the underlying implementation make changes as needed +// to support the different contexts. +export interface VisAugmenterEmbeddableConfig { + visLayerResourceIds?: string[]; + inFlyout?: boolean; + flyoutContext?: VisFlyoutContext; + leftValueAxisPadding?: boolean; + rightValueAxisPadding?: boolean; +} diff --git a/src/plugins/vis_augmenter/public/ui_actions_bootstrap.ts b/src/plugins/vis_augmenter/public/ui_actions_bootstrap.ts new file mode 100644 index 000000000000..27bd6284e71b --- /dev/null +++ b/src/plugins/vis_augmenter/public/ui_actions_bootstrap.ts @@ -0,0 +1,78 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + OpenEventsFlyoutAction, + ViewEventsOptionAction, + OPEN_EVENTS_FLYOUT_ACTION, + VIEW_EVENTS_OPTION_ACTION, +} from './view_events_flyout'; +import { CONTEXT_MENU_TRIGGER, EmbeddableContext } from '../../embeddable/public'; +import { SAVED_OBJECT_DELETE_TRIGGER } from '../../saved_objects_management/public'; +import { + externalActionTrigger, + EXTERNAL_ACTION_TRIGGER, + UiActionsSetup, +} from '../../ui_actions/public'; +import { ISavedAugmentVis } from './saved_augment_vis'; +import { VisLayer } from './types'; +import { + PLUGIN_RESOURCE_DELETE_ACTION, + PluginResourceDeleteAction, + SAVED_OBJECT_DELETE_ACTION, + SavedObjectDeleteAction, +} from './actions'; +import { PLUGIN_RESOURCE_DELETE_TRIGGER, pluginResourceDeleteTrigger } from './triggers'; + +export interface AugmentVisContext { + savedObjectId: string; +} + +export interface SavedObjectDeleteContext { + type: string; + savedObjectId: string; +} + +export interface PluginResourceDeleteContext { + savedObjs: ISavedAugmentVis[]; + visLayers: VisLayer[]; +} + +// Overriding the mappings defined in UIActions plugin so that +// the new trigger and action definitions resolve. +// This is a common pattern among internal Dashboards plugins. +declare module '../../ui_actions/public' { + export interface TriggerContextMapping { + [EXTERNAL_ACTION_TRIGGER]: AugmentVisContext; + [PLUGIN_RESOURCE_DELETE_TRIGGER]: PluginResourceDeleteContext; + } + + export interface ActionContextMapping { + [OPEN_EVENTS_FLYOUT_ACTION]: AugmentVisContext; + [VIEW_EVENTS_OPTION_ACTION]: EmbeddableContext; + [SAVED_OBJECT_DELETE_ACTION]: SavedObjectDeleteContext; + [PLUGIN_RESOURCE_DELETE_ACTION]: PluginResourceDeleteContext; + } +} + +export const bootstrapUiActions = (uiActions: UiActionsSetup) => { + const openEventsFlyoutAction = new OpenEventsFlyoutAction(); + const viewEventsOptionAction = new ViewEventsOptionAction(); + const savedObjectDeleteAction = new SavedObjectDeleteAction(); + const pluginResourceDeleteAction = new PluginResourceDeleteAction(); + + uiActions.registerAction(openEventsFlyoutAction); + uiActions.registerAction(viewEventsOptionAction); + uiActions.registerAction(savedObjectDeleteAction); + uiActions.registerAction(pluginResourceDeleteAction); + + uiActions.registerTrigger(externalActionTrigger); + uiActions.registerTrigger(pluginResourceDeleteTrigger); + + uiActions.addTriggerAction(EXTERNAL_ACTION_TRIGGER, openEventsFlyoutAction); + uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, viewEventsOptionAction); + uiActions.addTriggerAction(SAVED_OBJECT_DELETE_TRIGGER, savedObjectDeleteAction); + uiActions.addTriggerAction(PLUGIN_RESOURCE_DELETE_TRIGGER, pluginResourceDeleteAction); +}; diff --git a/src/plugins/vis_augmenter/public/utils/index.ts b/src/plugins/vis_augmenter/public/utils/index.ts new file mode 100644 index 000000000000..079132ce99d2 --- /dev/null +++ b/src/plugins/vis_augmenter/public/utils/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './utils'; diff --git a/src/plugins/vis_augmenter/public/utils/utils.test.ts b/src/plugins/vis_augmenter/public/utils/utils.test.ts new file mode 100644 index 000000000000..d8ebe41b087f --- /dev/null +++ b/src/plugins/vis_augmenter/public/utils/utils.test.ts @@ -0,0 +1,663 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Vis } from '../../../visualizations/public'; +import { + buildPipelineFromAugmentVisSavedObjs, + getAugmentVisSavedObjs, + getAnyErrors, + isEligibleForVisLayers, + createSavedAugmentVisLoader, + SavedObjectOpenSearchDashboardsServicesWithAugmentVis, + getMockAugmentVisSavedObjectClient, + generateAugmentVisSavedObject, + ISavedAugmentVis, + VisLayerTypes, + VisLayerExpressionFn, + cleanupStaleObjects, + VisLayer, + PluginResource, + VisLayerErrorTypes, + SavedObjectLoaderAugmentVis, +} from '../'; +import { PLUGIN_AUGMENTATION_ENABLE_SETTING } from '../../common/constants'; +import { AggConfigs } from '../../../data/common'; +import { uiSettingsServiceMock } from '../../../../core/public/mocks'; +import { setUISettings } from '../services'; +import { + STUB_INDEX_PATTERN_WITH_FIELDS, + TYPES_REGISTRY, + VALID_AGGS, + VALID_CONFIG_STATES, + VALID_VIS, + createPointInTimeEventsVisLayer, + createVisLayer, +} from '../mocks'; + +describe('utils', () => { + const uiSettingsMock = uiSettingsServiceMock.createStartContract(); + setUISettings(uiSettingsMock); + beforeEach(() => { + uiSettingsMock.get.mockImplementation((key: string) => { + return key === PLUGIN_AUGMENTATION_ENABLE_SETTING; + }); + }); + describe('isEligibleForVisLayers', () => { + it('vis is ineligible with invalid non-line type', async () => { + const vis = ({ + params: { + type: 'not-line', + seriesParams: [], + categoryAxes: [ + { + position: 'bottom', + }, + ], + }, + data: { + aggs: VALID_AGGS, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(false); + }); + it('vis is ineligible with no date_histogram', async () => { + const invalidConfigStates = [ + { + enabled: true, + type: 'histogram', + params: {}, + }, + { + enabled: true, + type: 'metrics', + params: {}, + }, + ]; + const invalidAggs = new AggConfigs(STUB_INDEX_PATTERN_WITH_FIELDS, invalidConfigStates, { + typesRegistry: TYPES_REGISTRY, + }); + const vis = ({ + params: { + type: 'line', + seriesParams: [], + }, + data: { + invalidAggs, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(false); + }); + it('vis is ineligible with invalid aggs counts', async () => { + const invalidConfigStates = [ + ...VALID_CONFIG_STATES, + { + enabled: true, + type: 'dot', + params: {}, + schema: 'radius', + }, + ]; + const invalidAggs = new AggConfigs(STUB_INDEX_PATTERN_WITH_FIELDS, invalidConfigStates, { + typesRegistry: TYPES_REGISTRY, + }); + const vis = ({ + params: { + type: 'line', + seriesParams: [], + }, + data: { + invalidAggs, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(false); + }); + it('vis is ineligible with no metric aggs', async () => { + const invalidConfigStates = [ + { + enabled: true, + type: 'date_histogram', + params: {}, + }, + ]; + const invalidAggs = new AggConfigs(STUB_INDEX_PATTERN_WITH_FIELDS, invalidConfigStates, { + typesRegistry: TYPES_REGISTRY, + }); + const vis = ({ + params: { + type: 'line', + seriesParams: [], + }, + data: { + invalidAggs, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(false); + }); + it('vis is ineligible with series param is not line type', async () => { + const vis = ({ + params: { + type: 'line', + seriesParams: [ + { + type: 'area', + }, + ], + categoryAxes: [ + { + position: 'bottom', + }, + ], + }, + data: { + aggs: VALID_AGGS, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(false); + }); + it('vis is ineligible with series param not all being line type', async () => { + const vis = ({ + params: { + type: 'line', + seriesParams: [ + { + type: 'area', + }, + { + type: 'line', + }, + ], + categoryAxes: [ + { + position: 'bottom', + }, + ], + }, + data: { + aggs: VALID_AGGS, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(vis)).toEqual(false); + }); + it('vis is ineligible with invalid x-axis due to no segment aggregation', async () => { + const badConfigStates = [ + { + enabled: true, + type: 'max', + params: {}, + schema: 'metric', + }, + { + enabled: true, + type: 'max', + params: {}, + schema: 'metric', + }, + ]; + const badAggs = new AggConfigs(STUB_INDEX_PATTERN_WITH_FIELDS, badConfigStates, { + typesRegistry: TYPES_REGISTRY, + }); + const invalidVis = ({ + params: { + type: 'line', + seriesParams: [ + { + type: 'line', + }, + ], + categoryAxes: [ + { + position: 'bottom', + }, + ], + }, + data: { + badAggs, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(invalidVis)).toEqual(false); + }); + it('vis is ineligible with xaxis not on bottom', async () => { + const invalidVis = ({ + params: { + type: 'line', + seriesParams: [ + { + type: 'line', + }, + ], + categoryAxes: [ + { + position: 'top', + }, + ], + }, + data: { + aggs: VALID_AGGS, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(invalidVis)).toEqual(false); + }); + it('vis is ineligible with no seriesParams', async () => { + const invalidVis = ({ + params: { + type: 'pie', + categoryAxes: [ + { + position: 'bottom', + }, + ], + }, + data: { + aggs: VALID_AGGS, + }, + } as unknown) as Vis; + expect(isEligibleForVisLayers(invalidVis)).toEqual(false); + }); + it('vis is ineligible with valid type and disabled setting', async () => { + uiSettingsMock.get.mockImplementation((key: string) => { + return key !== PLUGIN_AUGMENTATION_ENABLE_SETTING; + }); + expect(isEligibleForVisLayers(VALID_VIS)).toEqual(false); + }); + it('vis is eligible with valid type', async () => { + expect(isEligibleForVisLayers(VALID_VIS)).toEqual(true); + }); + }); + + describe('getAugmentVisSavedObjs', () => { + const fn = { + type: VisLayerTypes.PointInTimeEvents, + name: 'test-fn', + args: { + testArg: 'test-value', + }, + } as VisLayerExpressionFn; + const originPlugin = 'test-plugin'; + const pluginResource = { + type: 'test-plugin', + id: 'test-plugin-resource-id', + }; + const visId1 = 'test-vis-id-1'; + const visId2 = 'test-vis-id-2'; + const visId3 = 'test-vis-id-3'; + const obj1 = generateAugmentVisSavedObject( + 'valid-obj-id-1', + fn, + visId1, + originPlugin, + pluginResource + ); + const obj2 = generateAugmentVisSavedObject( + 'valid-obj-id-2', + fn, + visId1, + originPlugin, + pluginResource + ); + const obj3 = generateAugmentVisSavedObject( + 'valid-obj-id-3', + fn, + visId2, + originPlugin, + pluginResource + ); + + it('returns no matching saved objs when client returns empty list', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader)).length).toEqual(0); + }); + it('throws error when feature setting is disabled', async () => { + uiSettingsMock.get.mockImplementation((key: string) => { + return false; + }); + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + try { + await getAugmentVisSavedObjs(visId1, loader); + } catch (e: any) { + expect( + e.message.includes( + 'Visualization augmentation is disabled, please enable visualization:enablePluginAugmentation.' + ) + ); + } + }); + it('returns no matching saved objs when loader throws error', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: { + findAll: () => { + return new Error(); + }, + }, + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId3, loader)).length).toEqual(0); + }); + it('returns one matching saved obj', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader)).length).toEqual(1); + }); + it('returns multiple matching saved objs', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader)).length).toEqual(2); + }); + it('undefined plugin resource list has no effect', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader, undefined, undefined)).length).toEqual( + 2 + ); + }); + it('empty plugin resource list has no effect', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + expect((await getAugmentVisSavedObjs(visId1, loader, undefined, [])).length).toEqual(2); + }); + it('empty / undefined plugin resource list passes correct findAll() params', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + loader.findAll = jest.fn().mockImplementation(loader.findAll); + expect((await getAugmentVisSavedObjs(visId1, loader, undefined, [])).length).toEqual(2); + expect(loader.findAll).toHaveBeenCalledWith( + '', + 100, + [], + { + type: 'visualization', + id: visId1 as string, + }, + [] + ); + }); + it('single plugin resource is propagated to findAll()', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + loader.findAll = jest.fn().mockImplementation(loader.findAll); + expect( + (await getAugmentVisSavedObjs(visId1, loader, undefined, ['resource-1'])).length + ).toEqual(2); + expect(loader.findAll).toHaveBeenCalledWith( + 'resource-1', + 100, + [], + { + type: 'visualization', + id: visId1 as string, + }, + ['pluginResource.id'] + ); + }); + it('multiple plugin resources are propagated to findAll()', async () => { + const loader = createSavedAugmentVisLoader({ + savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1, obj2]), + } as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); + loader.findAll = jest.fn().mockImplementation(loader.findAll); + expect( + (await getAugmentVisSavedObjs(visId1, loader, undefined, ['resource-1', 'resource-2'])) + .length + ).toEqual(2); + expect(loader.findAll).toHaveBeenCalledWith( + 'resource-1|resource-2', + 100, + [], + { + type: 'visualization', + id: visId1 as string, + }, + ['pluginResource.id'] + ); + }); + }); + + describe('buildPipelineFromAugmentVisSavedObjs', () => { + const obj1 = { + title: 'obj1', + originPlugin: 'test-plugin', + pluginResource: { + type: 'test-resource-type', + id: 'obj-1-resource-id', + }, + visLayerExpressionFn: { + type: VisLayerTypes.PointInTimeEvents, + name: 'fn-1', + args: { + arg1: 'value-1', + }, + }, + } as ISavedAugmentVis; + const obj2 = { + title: 'obj2', + originPlugin: 'test-plugin', + pluginResource: { + type: 'test-resource-type', + id: 'obj-2-resource-id', + }, + visLayerExpressionFn: { + type: VisLayerTypes.PointInTimeEvents, + name: 'fn-2', + args: { + arg2: 'value-2', + }, + }, + } as ISavedAugmentVis; + it('catches error with empty array', async () => { + try { + buildPipelineFromAugmentVisSavedObjs([]); + } catch (e: any) { + expect( + e.message.includes( + 'Expression function from augment-vis saved objects could not be generated' + ) + ); + } + }); + it('builds with one saved obj', async () => { + const str = buildPipelineFromAugmentVisSavedObjs([obj1]); + expect(str).toEqual('fn-1 arg1="value-1"'); + }); + it('builds with multiple saved objs', async () => { + const str = buildPipelineFromAugmentVisSavedObjs([obj1, obj2]); + expect(str).toEqual(`fn-1 arg1="value-1"\n| fn-2 arg2="value-2"`); + }); + }); + + describe('getAnyErrors', () => { + const noErrorLayer1 = createVisLayer(VisLayerTypes.PointInTimeEvents, false); + const noErrorLayer2 = createVisLayer(VisLayerTypes.PointInTimeEvents, false); + const errorLayer1 = createVisLayer(VisLayerTypes.PointInTimeEvents, true, 'uh-oh!', { + type: 'resource-type-1', + id: '1234', + name: 'resource-1', + }); + const errorLayer2 = createVisLayer( + VisLayerTypes.PointInTimeEvents, + true, + 'oh no something terrible has happened :(', + { + type: 'resource-type-2', + id: '5678', + name: 'resource-2', + } + ); + const errorLayer3 = createVisLayer(VisLayerTypes.PointInTimeEvents, true, 'oops!', { + type: 'resource-type-1', + id: 'abcd', + name: 'resource-3', + }); + + it('empty array - returns undefined', async () => { + const err = getAnyErrors([], 'title-vis-title'); + expect(err).toEqual(undefined); + }); + it('single VisLayer no errors - returns undefined', async () => { + const err = getAnyErrors([noErrorLayer1], 'test-vis-title'); + expect(err).toEqual(undefined); + }); + it('multiple VisLayers no errors - returns undefined', async () => { + const err = getAnyErrors([noErrorLayer1, noErrorLayer2], 'test-vis-title'); + expect(err).toEqual(undefined); + }); + it('single VisLayer with error - returns formatted error', async () => { + const err = getAnyErrors([errorLayer1], 'test-vis-title'); + expect(err).not.toEqual(undefined); + expect(err?.stack).toStrictEqual(`-----resource-type-1-----\nID: 1234\nMessage: "uh-oh!"`); + }); + it('multiple VisLayers with errors - returns formatted error', async () => { + const err = getAnyErrors([errorLayer1, errorLayer2], 'test-vis-title'); + expect(err).not.toEqual(undefined); + expect(err?.stack).toStrictEqual( + `-----resource-type-1-----\nID: 1234\nMessage: "uh-oh!"\n\n\n` + + `-----resource-type-2-----\nID: 5678\nMessage: "oh no something terrible has happened :("` + ); + }); + it('multiple VisLayers with errors of same type - returns formatted error', async () => { + const err = getAnyErrors([errorLayer1, errorLayer3], 'test-vis-title'); + expect(err).not.toEqual(undefined); + expect(err?.stack).toStrictEqual( + `-----resource-type-1-----\nID: 1234\nMessage: "uh-oh!"\n\n` + `ID: abcd\nMessage: "oops!"` + ); + }); + it('VisLayers with and without error - returns formatted error', async () => { + const err = getAnyErrors([noErrorLayer1, errorLayer1], 'test-vis-title'); + expect(err).not.toEqual(undefined); + expect(err?.stack).toStrictEqual(`-----resource-type-1-----\nID: 1234\nMessage: "uh-oh!"`); + }); + }); + + describe('cleanupStaleObjects', () => { + const fn = { + type: VisLayerTypes.PointInTimeEvents, + name: 'test-fn', + args: { + testArg: 'test-value', + }, + } as VisLayerExpressionFn; + const originPlugin = 'test-plugin'; + const resourceId1 = 'resource-1'; + const resourceId2 = 'resource-2'; + const resourceType1 = 'resource-type-1'; + const augmentVisObj1 = generateAugmentVisSavedObject('id-1', fn, 'vis-id-1', originPlugin, { + type: resourceType1, + id: resourceId1, + }); + const augmentVisObj2 = generateAugmentVisSavedObject('id-2', fn, 'vis-id-1', originPlugin, { + type: resourceType1, + id: resourceId2, + }); + const resource1 = { + type: 'test-resource-type-1', + id: resourceId1, + name: 'resource-1', + urlPath: 'test-path', + } as PluginResource; + const resource2 = { + type: 'test-resource-type-1', + id: resourceId2, + name: 'resource-2', + urlPath: 'test-path', + } as PluginResource; + const validVisLayer1 = createPointInTimeEventsVisLayer(originPlugin, resource1, 1, false); + const staleVisLayer1 = { + ...createPointInTimeEventsVisLayer(originPlugin, resource1, 0, true), + error: { + type: VisLayerErrorTypes.RESOURCE_DELETED, + message: 'resource is deleted', + }, + }; + const staleVisLayer2 = { + ...createPointInTimeEventsVisLayer(originPlugin, resource2, 0, true), + error: { + type: VisLayerErrorTypes.RESOURCE_DELETED, + message: 'resource is deleted', + }, + }; + + it('no augment-vis objs, no vislayers', async () => { + const mockDeleteFn = jest.fn(); + const augmentVisObjs = [] as ISavedAugmentVis[]; + const visLayers = [] as VisLayer[]; + const augmentVisLoader = createSavedAugmentVisLoader({ + savedObjectsClient: { + ...getMockAugmentVisSavedObjectClient(augmentVisObjs), + delete: mockDeleteFn, + }, + } as any) as SavedObjectLoaderAugmentVis; + + cleanupStaleObjects(augmentVisObjs, visLayers, augmentVisLoader); + + expect(mockDeleteFn).toHaveBeenCalledTimes(0); + }); + it('no stale vislayers', async () => { + const mockDeleteFn = jest.fn(); + const augmentVisObjs = [augmentVisObj1]; + const visLayers = [validVisLayer1]; + const augmentVisLoader = createSavedAugmentVisLoader({ + savedObjectsClient: { + ...getMockAugmentVisSavedObjectClient(augmentVisObjs), + delete: mockDeleteFn, + }, + } as any) as SavedObjectLoaderAugmentVis; + + cleanupStaleObjects(augmentVisObjs, visLayers, augmentVisLoader); + + expect(mockDeleteFn).toHaveBeenCalledTimes(0); + }); + it('1 stale vislayer', async () => { + const mockDeleteFn = jest.fn(); + const augmentVisObjs = [augmentVisObj1]; + const visLayers = [staleVisLayer1]; + const augmentVisLoader = createSavedAugmentVisLoader({ + savedObjectsClient: { + ...getMockAugmentVisSavedObjectClient(augmentVisObjs), + delete: mockDeleteFn, + }, + } as any) as SavedObjectLoaderAugmentVis; + + cleanupStaleObjects(augmentVisObjs, visLayers, augmentVisLoader); + + expect(mockDeleteFn).toHaveBeenCalledTimes(1); + }); + it('multiple stale vislayers', async () => { + const mockDeleteFn = jest.fn(); + const augmentVisObjs = [augmentVisObj1, augmentVisObj2]; + const visLayers = [staleVisLayer1, staleVisLayer2]; + const augmentVisLoader = createSavedAugmentVisLoader({ + savedObjectsClient: { + ...getMockAugmentVisSavedObjectClient(augmentVisObjs), + delete: mockDeleteFn, + }, + } as any) as SavedObjectLoaderAugmentVis; + + cleanupStaleObjects(augmentVisObjs, visLayers, augmentVisLoader); + + expect(mockDeleteFn).toHaveBeenCalledTimes(2); + }); + it('stale and valid vislayers', async () => { + const mockDeleteFn = jest.fn(); + const augmentVisObjs = [augmentVisObj1, augmentVisObj2]; + const visLayers = [validVisLayer1, staleVisLayer2]; + const augmentVisLoader = createSavedAugmentVisLoader({ + savedObjectsClient: { + ...getMockAugmentVisSavedObjectClient(augmentVisObjs), + delete: mockDeleteFn, + }, + } as any) as SavedObjectLoaderAugmentVis; + + cleanupStaleObjects(augmentVisObjs, visLayers, augmentVisLoader); + + expect(mockDeleteFn).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/src/plugins/vis_augmenter/public/utils/utils.ts b/src/plugins/vis_augmenter/public/utils/utils.ts new file mode 100644 index 000000000000..f1c18ce15b79 --- /dev/null +++ b/src/plugins/vis_augmenter/public/utils/utils.ts @@ -0,0 +1,183 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get, isEmpty } from 'lodash'; +import { Vis } from '../../../../plugins/visualizations/public'; +import { + formatExpression, + buildExpressionFunction, + buildExpression, + ExpressionAstFunctionBuilder, +} from '../../../../plugins/expressions/public'; +import { + ISavedAugmentVis, + SavedAugmentVisLoader, + VisLayerFunctionDefinition, + VisLayer, + isVisLayerWithError, + VisLayerErrorTypes, +} from '../'; +import { PLUGIN_AUGMENTATION_ENABLE_SETTING } from '../../common/constants'; +import { getUISettings } from '../services'; +import { IUiSettingsClient } from '../../../../core/public'; + +export const isEligibleForVisLayers = (vis: Vis, uiSettingsClient?: IUiSettingsClient): boolean => { + // Only support date histogram and ensure there is only 1 x-axis and it has to be on the bottom. + // Additionally to have a valid x-axis, there needs to be a segment aggregation + const hasValidXaxis = + vis.data?.aggs !== undefined && + vis.data.aggs?.byTypeName('date_histogram').length === 1 && + vis.params.categoryAxes.length === 1 && + vis.params.categoryAxes[0].position === 'bottom' && + vis.data.aggs?.bySchemaName('segment').length > 0; + // Support 1 segment for x axis bucket (that is date_histogram) and support metrics for + // multiple supported yaxis only. If there are other aggregation types, this is not + // valid for augmentation + const hasCorrectAggregationCount = + vis.data?.aggs !== undefined && + vis.data.aggs?.bySchemaName('metric').length > 0 && + vis.data.aggs?.bySchemaName('metric').length === vis.data.aggs?.aggs.length - 1; + const hasOnlyLineSeries = + vis.params?.seriesParams !== undefined && + vis.params?.seriesParams?.every( + (seriesParam: { type: string }) => seriesParam.type === 'line' + ) && + vis.params?.type === 'line'; + + // Checks if the augmentation setting is enabled + const config = uiSettingsClient ?? getUISettings(); + const isAugmentationEnabled = config.get(PLUGIN_AUGMENTATION_ENABLE_SETTING); + return isAugmentationEnabled && hasValidXaxis && hasCorrectAggregationCount && hasOnlyLineSeries; +}; + +/** + * Using a SavedAugmentVisLoader, fetch all saved objects that are of 'augment-vis' type. + * Filter by vis ID by passing in a 'hasReferences' obj with the vis ID to the findAll() fn call, + * and optionally by plugin resource ID list, if specified. + */ +export const getAugmentVisSavedObjs = async ( + visId: string | undefined, + loader: SavedAugmentVisLoader | undefined, + uiSettings?: IUiSettingsClient | undefined, + pluginResourceIds?: string[] | undefined +): Promise => { + // Using optional services provided, or the built-in services from this plugin + const config = uiSettings !== undefined ? uiSettings : getUISettings(); + const isAugmentationEnabled = config.get(PLUGIN_AUGMENTATION_ENABLE_SETTING); + if (!isAugmentationEnabled) { + throw new Error( + 'Visualization augmentation is disabled, please enable visualization:enablePluginAugmentation.' + ); + } + try { + // If there is specified plugin resource IDs, add a search string and search field + // into findAll() fn call + const pluginResourceIdsSpecified = + pluginResourceIds !== undefined && pluginResourceIds.length > 0; + const resp = await loader?.findAll( + pluginResourceIdsSpecified ? pluginResourceIds.join('|') : '', + 100, + [], + { + type: 'visualization', + id: visId as string, + }, + pluginResourceIdsSpecified ? ['pluginResource.id'] : [] + ); + return (get(resp, 'hits', []) as any[]) as ISavedAugmentVis[]; + } catch (e) { + return [] as ISavedAugmentVis[]; + } +}; + +/** + * Given an array of augment-vis saved objects that contain expression function details, + * construct a pipeline that will execute each of these expression functions. + * Note that the order does not matter; each expression function should be taking + * in the current output and appending its results to it, such that the end result + * contains the results from each expression function that was ran. + */ +export const buildPipelineFromAugmentVisSavedObjs = (objs: ISavedAugmentVis[]): string => { + try { + const visLayerExpressionFns = objs.map((obj: ISavedAugmentVis) => + buildExpressionFunction( + obj.visLayerExpressionFn.name, + obj.visLayerExpressionFn.args + ) + ) as Array>; + const ast = buildExpression(visLayerExpressionFns).toAst(); + return formatExpression(ast); + } catch (e) { + throw new Error('Expression function from augment-vis saved objects could not be generated'); + } +}; + +/** + * Returns an error with an aggregated message about all of the + * errors found in the set of VisLayers. If no errors, returns undefined. + */ +export const getAnyErrors = (visLayers: VisLayer[], visTitle: string): Error | undefined => { + const visLayersWithErrors = visLayers.filter((visLayer) => isVisLayerWithError(visLayer)); + if (!isEmpty(visLayersWithErrors)) { + // Aggregate by unique plugin resource type + const resourceTypes = [ + ...new Set(visLayersWithErrors.map((visLayer) => visLayer.pluginResource.type)), + ]; + + let msgDetails = ''; + resourceTypes.forEach((type, index) => { + const matchingVisLayers = visLayersWithErrors.filter( + (visLayer) => visLayer.pluginResource.type === type + ); + if (index !== 0) msgDetails += '\n\n\n'; + msgDetails += `-----${type}-----`; + matchingVisLayers.forEach((visLayer, idx) => { + if (idx !== 0) msgDetails += '\n'; + msgDetails += `\nID: ${visLayer.pluginResource.id}`; + msgDetails += `\nMessage: "${visLayer.error?.message}"`; + }); + }); + + const err = new Error(`Certain plugin resources failed to load on the ${visTitle} chart`); + // We set as the stack here so it can be parsed and shown cleanly in the details modal coming from the error toast notification. + err.stack = msgDetails; + return err; + } else { + return undefined; + } +}; + +/** + * Cleans up any stale saved objects caused by plugin resources being deleted. Kicks + * off an async call to delete the stale objs. + * + * @param augmentVisSavedObs the original augment-vis saved objs for this particular vis + * @param visLayers the produced VisLayers containing details if the resource has been deleted + * @param visualizationsLoader the visualizations saved object loader to handle deletion + */ + +export const cleanupStaleObjects = ( + augmentVisSavedObjs: ISavedAugmentVis[], + visLayers: VisLayer[], + loader: SavedAugmentVisLoader | undefined +): void => { + const staleVisLayers = visLayers + .filter((visLayer) => isVisLayerWithError(visLayer)) + .filter( + (visLayerWithError) => visLayerWithError.error?.type === VisLayerErrorTypes.RESOURCE_DELETED + ); + if (!isEmpty(staleVisLayers)) { + const objIdsToDelete = [] as string[]; + staleVisLayers.forEach((staleVisLayer) => { + // Match the VisLayer to its origin saved obj to extract the to-be-deleted saved obj ID + const deletedPluginResourceId = staleVisLayer.pluginResource.id; + const savedObjId = augmentVisSavedObjs.find( + (savedObj) => savedObj.pluginResource.id === deletedPluginResourceId + )?.id; + if (savedObjId !== undefined) objIdsToDelete.push(savedObjId); + }); + loader?.delete(objIdsToDelete); + } +}; diff --git a/src/plugins/vis_augmenter/public/vega/README.md b/src/plugins/vis_augmenter/public/vega/README.md new file mode 100644 index 000000000000..fef45af1777a --- /dev/null +++ b/src/plugins/vis_augmenter/public/vega/README.md @@ -0,0 +1 @@ +Contains the helper functions that are optionally used when rendering vega charts that are eligible for rendering with VisLayers. diff --git a/src/plugins/vis_augmenter/public/vega/constants.ts b/src/plugins/vis_augmenter/public/vega/constants.ts new file mode 100644 index 000000000000..a5729725422e --- /dev/null +++ b/src/plugins/vis_augmenter/public/vega/constants.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export enum VisAnnotationType { + POINT_IN_TIME_ANNOTATION = 'POINT_IN_TIME_ANNOTATION', +} diff --git a/src/plugins/vis_augmenter/public/vega/helpers.test.ts b/src/plugins/vis_augmenter/public/vega/helpers.test.ts new file mode 100644 index 000000000000..2e746950f71c --- /dev/null +++ b/src/plugins/vis_augmenter/public/vega/helpers.test.ts @@ -0,0 +1,618 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { cloneDeep } from 'lodash'; +import { + OpenSearchDashboardsDatatable, + OpenSearchDashboardsDatatableColumn, +} from '../../../expressions/public'; +import { YAxisConfig } from '../../../vis_type_vega/public'; +import { + enableVisLayersInSpecConfig, + isVisLayerColumn, + generateVisLayerFilterString, + addMissingRowsToTableBounds, + addPointInTimeEventsLayersToTable, + addPointInTimeEventsLayersToSpec, + generateVisLayerTooltipFields, + addVisEventSignalsToSpecConfig, + calculateYAxisPadding, + augmentEventChartSpec, +} from './helpers'; +import { + VIS_LAYER_COLUMN_TYPE, + VisLayerTypes, + PointInTimeEventsVisLayer, + VisLayer, + VisFlyoutContext, + VisAugmenterEmbeddableConfig, +} from '../'; +import { + TEST_DATATABLE_MULTIPLE_VIS_LAYERS, + TEST_DATATABLE_MULTIPLE_VIS_LAYERS_ONE_EMPTY, + TEST_DATATABLE_NO_VIS_LAYERS, + TEST_DATATABLE_ONLY_VIS_LAYERS, + TEST_DATATABLE_SINGLE_ROW_NO_VIS_LAYERS, + TEST_DATATABLE_SINGLE_ROW_SINGLE_VIS_LAYER, + TEST_DATATABLE_SINGLE_VIS_LAYER, + TEST_DATATABLE_SINGLE_VIS_LAYER_EMPTY, + TEST_DATATABLE_SINGLE_VIS_LAYER_ON_BOUNDS, + TEST_DIMENSIONS, + TEST_DIMENSIONS_INVALID_BOUNDS, + TEST_DIMENSIONS_SINGLE_ROW, + TEST_RESULT_SPEC_MULTIPLE_VIS_LAYERS, + TEST_RESULT_SPEC_SINGLE_VIS_LAYER, + TEST_RESULT_SPEC_SINGLE_VIS_LAYER_EMPTY, + TEST_SPEC_MULTIPLE_VIS_LAYERS, + TEST_SPEC_NO_VIS_LAYERS, + TEST_SPEC_SINGLE_VIS_LAYER, + TEST_VIS_LAYERS_MULTIPLE, + TEST_VIS_LAYERS_MULTIPLE_ONE_EMPTY, + TEST_VIS_LAYERS_SINGLE, + TEST_VIS_LAYERS_SINGLE_INVALID_BOUNDS, + TEST_VIS_LAYERS_SINGLE_ON_BOUNDS, +} from '../test_constants'; + +describe('helpers', function () { + describe('enableVisLayersInSpecConfig()', function () { + const pointInTimeEventsVisLayer = { + type: VisLayerTypes.PointInTimeEvents, + originPlugin: 'test-plugin', + pluginResource: { + type: 'test-resource-type', + id: 'test-resource-id', + name: 'test-resource-name', + urlPath: 'test-resource-url-path', + }, + events: [ + { + timestamp: 1234, + metadata: { + pluginResourceId: 'test-resource-id', + }, + }, + ], + } as PointInTimeEventsVisLayer; + const invalidVisLayer = ({ + type: 'something-invalid', + originPlugin: 'test-plugin', + pluginResource: { + type: 'test-resource-type', + id: 'test-resource-id', + name: 'test-resource-name', + urlPath: 'test-resource-url-path', + }, + } as unknown) as VisLayer; + + it('updates config with just a valid Vislayer', function () { + const baseConfig = { + kibana: { + hideWarnings: true, + }, + }; + const updatedConfig = enableVisLayersInSpecConfig({ config: baseConfig }, [ + pointInTimeEventsVisLayer, + ]); + const expectedArr = [ + ...new Map([[VisLayerTypes.PointInTimeEvents, true]]), + ]; + // @ts-ignore + baseConfig.kibana.visibleVisLayers = expectedArr; + expect(updatedConfig).toStrictEqual(baseConfig); + }); + it('updates config with a valid and invalid VisLayer', function () { + const baseConfig = { + kibana: { + hideWarnings: true, + }, + }; + const updatedConfig = enableVisLayersInSpecConfig({ config: baseConfig }, [ + pointInTimeEventsVisLayer, + invalidVisLayer, + ]); + const expectedArr = [ + ...new Map([[VisLayerTypes.PointInTimeEvents, true]]), + ]; + // @ts-ignore + baseConfig.kibana.visibleVisLayers = expectedArr; + expect(updatedConfig).toStrictEqual(baseConfig); + }); + it('does not update config if no valid VisLayer', function () { + const baseConfig = { + kibana: { + hideWarnings: true, + }, + }; + const updatedConfig = enableVisLayersInSpecConfig({ config: baseConfig }, [invalidVisLayer]); + // @ts-ignore + baseConfig.kibana.visibleVisLayers = [...new Map()]; + expect(updatedConfig).toStrictEqual(baseConfig); + }); + it('does not update config if empty VisLayer list', function () { + const baseConfig = { + kibana: { + hideWarnings: true, + }, + }; + const updatedConfig = enableVisLayersInSpecConfig({ config: baseConfig }, []); + // @ts-ignore + baseConfig.kibana.visibleVisLayers = [...new Map()]; + expect(updatedConfig).toStrictEqual(baseConfig); + }); + }); + + describe('isVisLayerColumn()', function () { + it('return false for column with invalid type', function () { + const column = { + id: 'test-id', + name: 'test-name', + meta: { + type: 'invalid-type', + }, + } as OpenSearchDashboardsDatatableColumn; + expect(isVisLayerColumn(column)).toBe(false); + }); + it('return false for column with no meta field', function () { + const column = { + id: 'test-id', + name: 'test-name', + } as OpenSearchDashboardsDatatableColumn; + expect(isVisLayerColumn(column)).toBe(false); + }); + it('return true for column with valid type', function () { + const column = { + id: 'test-id', + name: 'test-name', + meta: { + type: VIS_LAYER_COLUMN_TYPE, + }, + } as OpenSearchDashboardsDatatableColumn; + expect(isVisLayerColumn(column)).toBe(true); + }); + }); + + describe('generateVisLayerFilterString()', function () { + it('empty array returns false', function () { + const visLayerColumnIds = [] as string[]; + const filterString = 'false'; + expect(generateVisLayerFilterString(visLayerColumnIds)).toStrictEqual(filterString); + }); + it('array with one value returns correct filter string', function () { + const visLayerColumnIds = ['test-id-1']; + const filterString = `datum['test-id-1'] > 0`; + expect(generateVisLayerFilterString(visLayerColumnIds)).toStrictEqual(filterString); + }); + it('array with multiple values returns correct filter string', function () { + const visLayerColumnIds = ['test-id-1', 'test-id-2']; + const filterString = `datum['test-id-1'] > 0 || datum['test-id-2'] > 0`; + expect(generateVisLayerFilterString(visLayerColumnIds)).toStrictEqual(filterString); + }); + }); + + describe('generateVisLayerTooltipFields()', function () { + it('empty array returns empty', function () { + const visLayerColumnIds = [] as string[]; + const tooltipFields = [] as Array<{ field: string }>; + expect(generateVisLayerTooltipFields(visLayerColumnIds)).toStrictEqual(tooltipFields); + }); + it('array with one value returns correct array', function () { + const visLayerColumnIds = ['test-id-1']; + const tooltipFields = [{ field: 'test-id-1' }]; + expect(generateVisLayerTooltipFields(visLayerColumnIds)).toStrictEqual(tooltipFields); + }); + it('array with multiple values returns correct array', function () { + const visLayerColumnIds = ['test-id-1', 'test-id-2']; + const tooltipFields = [{ field: 'test-id-1' }, { field: 'test-id-2' }]; + expect(generateVisLayerTooltipFields(visLayerColumnIds)).toStrictEqual(tooltipFields); + }); + }); + + describe('addMissingRowsToTableBounds()', function () { + const columnId = 'test-id'; + const columnName = 'test-name'; + const allRows = [ + { + [columnId]: 1, + }, + { + [columnId]: 2, + }, + { + [columnId]: 3, + }, + { + [columnId]: 4, + }, + { + [columnId]: 5, + }, + ]; + it('adds single row if start/end times are the same', function () { + const datatable = { + type: 'opensearch_dashboards_datatable', + columns: [ + { + id: columnId, + name: columnName, + }, + ], + rows: [], + } as OpenSearchDashboardsDatatable; + const dimensions = { + x: { + params: { + interval: 1, + bounds: { + min: 1, + max: 1, + }, + }, + label: columnName, + }, + }; + const result = addMissingRowsToTableBounds(datatable, dimensions); + const expectedTable = { + ...datatable, + rows: [allRows[0]], + }; + expect(result).toStrictEqual(expectedTable); + }); + it('adds all rows if there is none to begin with', function () { + const datatable = { + type: 'opensearch_dashboards_datatable', + columns: [ + { + id: columnId, + name: columnName, + }, + ], + rows: [], + } as OpenSearchDashboardsDatatable; + const dimensions = { + x: { + params: { + interval: 1, + bounds: { + min: 1, + max: 5, + }, + }, + label: columnName, + }, + }; + const result = addMissingRowsToTableBounds(datatable, dimensions); + const expectedTable = { + ...datatable, + rows: allRows, + }; + expect(result).toStrictEqual(expectedTable); + }); + it('fill rows at beginning', function () { + const missingRows = cloneDeep(allRows); + missingRows.shift(); + missingRows.shift(); + const datatable = { + type: 'opensearch_dashboards_datatable', + columns: [ + { + id: columnId, + name: columnName, + }, + ], + rows: missingRows, + } as OpenSearchDashboardsDatatable; + const dimensions = { + x: { + params: { + interval: 1, + bounds: { + min: 1, + max: 5, + }, + }, + label: columnName, + }, + }; + const result = addMissingRowsToTableBounds(datatable, dimensions); + const expectedTable = { + ...datatable, + rows: allRows, + }; + expect(result).toStrictEqual(expectedTable); + }); + it('fill rows at end', function () { + const missingRows = cloneDeep(allRows); + missingRows.pop(); + missingRows.pop(); + const datatable = { + type: 'opensearch_dashboards_datatable', + columns: [ + { + id: columnId, + name: columnName, + }, + ], + rows: missingRows, + } as OpenSearchDashboardsDatatable; + const dimensions = { + x: { + params: { + interval: 1, + bounds: { + min: 1, + max: 5, + }, + }, + label: columnName, + }, + }; + const result = addMissingRowsToTableBounds(datatable, dimensions); + const expectedTable = { + ...datatable, + rows: allRows, + }; + expect(result).toStrictEqual(expectedTable); + }); + }); + + describe('addPointInTimeEventsLayersToTable()', function () { + it('single vis layer is added correctly', function () { + expect( + addPointInTimeEventsLayersToTable( + TEST_DATATABLE_NO_VIS_LAYERS, + TEST_DIMENSIONS, + TEST_VIS_LAYERS_SINGLE + ) + ).toStrictEqual(TEST_DATATABLE_SINGLE_VIS_LAYER); + }); + it('multiple vis layers are added correctly', function () { + expect( + addPointInTimeEventsLayersToTable( + TEST_DATATABLE_NO_VIS_LAYERS, + TEST_DIMENSIONS, + TEST_VIS_LAYERS_MULTIPLE + ) + ).toStrictEqual(TEST_DATATABLE_MULTIPLE_VIS_LAYERS); + }); + it('invalid bounds adds no row data', function () { + expect( + addPointInTimeEventsLayersToTable( + { + ...TEST_DATATABLE_NO_VIS_LAYERS, + rows: [], + }, + TEST_DIMENSIONS_INVALID_BOUNDS, + TEST_VIS_LAYERS_SINGLE + ) + ).toStrictEqual({ + ...TEST_DATATABLE_NO_VIS_LAYERS, + rows: [], + }); + }); + it('vis layers with single row are added correctly', function () { + expect( + addPointInTimeEventsLayersToTable( + TEST_DATATABLE_SINGLE_ROW_NO_VIS_LAYERS, + TEST_DIMENSIONS_SINGLE_ROW, + TEST_VIS_LAYERS_SINGLE + ) + ).toStrictEqual(TEST_DATATABLE_SINGLE_ROW_SINGLE_VIS_LAYER); + }); + it('vis layers with no existing rows/data are added correctly', function () { + expect( + addPointInTimeEventsLayersToTable( + { + ...TEST_DATATABLE_NO_VIS_LAYERS, + rows: [], + }, + TEST_DIMENSIONS, + TEST_VIS_LAYERS_SINGLE + ) + ).toStrictEqual(TEST_DATATABLE_ONLY_VIS_LAYERS); + }); + it('vis layers with one having events and the other empty are added correctly', function () { + expect( + addPointInTimeEventsLayersToTable( + TEST_DATATABLE_NO_VIS_LAYERS, + + TEST_DIMENSIONS, + TEST_VIS_LAYERS_MULTIPLE_ONE_EMPTY + ) + ).toStrictEqual(TEST_DATATABLE_MULTIPLE_VIS_LAYERS_ONE_EMPTY); + }); + it('vis layer with out-of-bounds timestamps are not added', function () { + expect( + addPointInTimeEventsLayersToTable( + TEST_DATATABLE_NO_VIS_LAYERS, + TEST_DIMENSIONS, + TEST_VIS_LAYERS_SINGLE_INVALID_BOUNDS + ) + ).toStrictEqual(TEST_DATATABLE_SINGLE_VIS_LAYER_EMPTY); + }); + it('vis layer with events on edge of bounds are added', function () { + expect( + addPointInTimeEventsLayersToTable( + TEST_DATATABLE_NO_VIS_LAYERS, + TEST_DIMENSIONS, + TEST_VIS_LAYERS_SINGLE_ON_BOUNDS + ) + ).toStrictEqual(TEST_DATATABLE_SINGLE_VIS_LAYER_ON_BOUNDS); + }); + }); + + describe('addPointInTimeEventsLayersToSpec()', function () { + it('spec with single time series produces correct spec', function () { + const expectedSpec = TEST_RESULT_SPEC_SINGLE_VIS_LAYER; + const returnSpec = addPointInTimeEventsLayersToSpec( + TEST_DATATABLE_SINGLE_VIS_LAYER, + TEST_DIMENSIONS, + TEST_SPEC_SINGLE_VIS_LAYER + ); + // deleting the scale fields since this contain generated + // fields based on timezone env it is run in + delete expectedSpec.vconcat[1].encoding.x.scale; + delete returnSpec.vconcat[1].encoding.x.scale; + expect(returnSpec).toEqual(expectedSpec); + }); + it('spec with multiple time series produces correct spec', function () { + const expectedSpec = TEST_RESULT_SPEC_MULTIPLE_VIS_LAYERS; + const returnSpec = addPointInTimeEventsLayersToSpec( + TEST_DATATABLE_MULTIPLE_VIS_LAYERS, + TEST_DIMENSIONS, + TEST_SPEC_MULTIPLE_VIS_LAYERS + ); + // deleting the scale fields since this contain generated + // fields based on timezone env it is run in + delete expectedSpec.vconcat[1].encoding.x.scale; + delete returnSpec.vconcat[1].encoding.x.scale; + expect(returnSpec).toEqual(expectedSpec); + }); + it('spec with vis layers with empty data produces correct spec', function () { + const expectedSpec = TEST_RESULT_SPEC_SINGLE_VIS_LAYER_EMPTY; + const returnSpec = addPointInTimeEventsLayersToSpec( + TEST_DATATABLE_SINGLE_VIS_LAYER_EMPTY, + TEST_DIMENSIONS, + TEST_SPEC_NO_VIS_LAYERS + ); + // deleting the scale fields since this contain generated + // fields based on timezone env it is run in + delete expectedSpec.vconcat[1].encoding.x.scale; + delete returnSpec.vconcat[1].encoding.x.scale; + expect(returnSpec).toEqual(expectedSpec); + }); + }); + + describe('addVisEventSignalsToSpecConfig()', () => { + it('vis event signal is added for point in time annotations', () => { + const startSpec = { + kibana: {}, + }; + const endSpec = addVisEventSignalsToSpecConfig(startSpec); + expect(endSpec.kibana.signals.POINT_IN_TIME_ANNOTATION.length).toBeGreaterThan(0); + }); + it('tooltip configuration is specified', () => { + const startSpec = { + kibana: {}, + }; + const endSpec = addVisEventSignalsToSpecConfig(startSpec); + expect(endSpec.tooltips).not.toBeNull(); + }); + }); + + describe('calculateYAxisPadding()', () => { + it('calculation includes sum of all y axis fields', () => { + const sampleConfig = { + minExtent: 1, + offset: 1, + translate: 1, + domainWidth: 1, + labelPadding: 1, + titlePadding: 1, + tickOffset: 1, + tickSize: 1, + } as YAxisConfig; + // derived from each value in sample config + default padding of 3 + expect(calculateYAxisPadding(sampleConfig)).toEqual(11); + }); + it('calculation defaults to 0 for missing y axis fields', () => { + const sampleConfig = { + minExtent: 1, + } as YAxisConfig; + // derived from each value in sample config + default padding of 3 + expect(calculateYAxisPadding(sampleConfig)).toEqual(4); + }); + }); + + describe('augmentEventChartSpec()', () => { + it('not in flyout - no change', () => { + const config = { + inFlyout: false, + flyoutContext: VisFlyoutContext.BASE_VIS, + } as VisAugmenterEmbeddableConfig; + const origSpec = { + config: { some: 'config' }, + vconcat: [{ base: 'vis' }, { event: 'vis' }], + }; + + expect(augmentEventChartSpec(config, origSpec)).toEqual(origSpec); + }); + it('in flyout + base vis context', () => { + const config = { + inFlyout: true, + flyoutContext: VisFlyoutContext.BASE_VIS, + } as VisAugmenterEmbeddableConfig; + const origSpec = { + config: { some: 'config' }, + vconcat: [{ base: 'vis' }, { event: 'vis' }], + }; + + const returnSpec = augmentEventChartSpec(config, origSpec) as any; + // legend should be forced to the top + expect(returnSpec.config.legend.orient).toEqual('top'); + // y-axis should be a set, consistent, nonzero width + expect(returnSpec.config.axisY.minExtent).toBeGreaterThan(0); + expect(returnSpec.config.axisY.maxExtent).toBeGreaterThan(0); + expect(returnSpec.config.axisY.offset).toEqual(0); + expect(returnSpec.vconcat.length).toEqual(2); + }); + it('in flyout + event vis context', () => { + const config = { + inFlyout: true, + flyoutContext: VisFlyoutContext.EVENT_VIS, + } as VisAugmenterEmbeddableConfig; + const origSpec = { + config: { some: 'config' }, + vconcat: [ + { base: 'vis' }, + { + event: 'vis', + encoding: { + x: { + axis: { + some: 'field', + }, + }, + }, + mark: { + some: 'other-field', + }, + }, + ], + }; + + const returnSpec = augmentEventChartSpec(config, origSpec) as any; + const xAxisConfig = returnSpec.vconcat[0].encoding.x.axis; + // y-axis should be a set, consistent, nonzero width + expect(returnSpec.config.axisY.minExtent).toBeGreaterThan(0); + expect(returnSpec.config.axisY.maxExtent).toBeGreaterThan(0); + expect(returnSpec.config.axisY.offset).toEqual(0); + // x-axis should be hidden + expect(xAxisConfig.grid).toEqual(false); + expect(xAxisConfig.ticks).toEqual(false); + expect(xAxisConfig.labels).toEqual(false); + expect(xAxisConfig.title).toEqual(null); + expect(returnSpec.vconcat.length).toEqual(1); + }); + it('in flyout + timeline vis context', () => { + const config = { + inFlyout: true, + flyoutContext: VisFlyoutContext.TIMELINE_VIS, + } as VisAugmenterEmbeddableConfig; + const origSpec = { + config: { some: 'config' }, + vconcat: [{ base: 'vis' }, { event: 'vis' }], + }; + + const returnSpec = augmentEventChartSpec(config, origSpec) as any; + // y-axis should be a set, consistent, nonzero width + expect(returnSpec.config.axisY.minExtent).toBeGreaterThan(0); + expect(returnSpec.config.axisY.maxExtent).toBeGreaterThan(0); + expect(returnSpec.config.axisY.offset).toEqual(0); + // should have transform param set on the event chart + expect(returnSpec.vconcat[0].transform.length).toBeGreaterThan(0); + expect(returnSpec.vconcat.length).toEqual(1); + }); + }); +}); diff --git a/src/plugins/vis_augmenter/public/vega/helpers.ts b/src/plugins/vis_augmenter/public/vega/helpers.ts new file mode 100644 index 000000000000..de1e03d57632 --- /dev/null +++ b/src/plugins/vis_augmenter/public/vega/helpers.ts @@ -0,0 +1,503 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import moment from 'moment'; +import { cloneDeep, isEmpty, get } from 'lodash'; +import { YAxisConfig } from 'src/plugins/vis_type_vega/public'; +import { + OpenSearchDashboardsDatatable, + OpenSearchDashboardsDatatableColumn, +} from '../../../expressions/public'; +import { + PointInTimeEvent, + PointInTimeEventsVisLayer, + isPointInTimeEventsVisLayer, + VIS_LAYER_COLUMN_TYPE, + EVENT_COLOR, + EVENT_MARK_SIZE, + EVENT_MARK_SIZE_ENLARGED, + EVENT_MARK_SHAPE, + EVENT_TIMELINE_HEIGHT, + EVENT_TOOLTIP_CENTER_ON_MARK, + HOVER_PARAM, + VisLayer, + VisLayers, + VisLayerTypes, + VisAugmenterEmbeddableConfig, + VisFlyoutContext, +} from '../'; +import { VisAnnotationType } from './constants'; + +// Given any visLayers, create a map to indicate which VisLayer types are present. +// Convert to an array since ES6 Maps cannot be stringified. +export const enableVisLayersInSpecConfig = (spec: object, visLayers: VisLayers): {} => { + const config = get(spec, 'config', { kibana: {} }); + const visibleVisLayers = new Map(); + + // Currently only support PointInTimeEventsVisLayers. Set the flag to true + // if there are any + const pointInTimeEventsVisLayers = visLayers.filter((visLayer: VisLayer) => + isPointInTimeEventsVisLayer(visLayer) + ) as PointInTimeEventsVisLayer[]; + if (!isEmpty(pointInTimeEventsVisLayers)) { + visibleVisLayers.set(VisLayerTypes.PointInTimeEvents, true); + } + return { + ...config, + kibana: { + ...config.kibana, + visibleVisLayers: [...visibleVisLayers], + }, + }; +}; + +/** + * Adds the signals which vega will use to trigger required events on the point in time annotation marks + */ +export const addVisEventSignalsToSpecConfig = (spec: object) => { + const config = get(spec, 'config', { kibana: {} }); + const signals = { + ...(config.kibana.signals || {}), + [`${VisAnnotationType.POINT_IN_TIME_ANNOTATION}`]: [ + { + name: 'PointInTimeAnnotationVisEvent', + on: [{ events: 'click', update: 'opensearchDashboardsVisEventTriggered(event, datum)' }], + }, + ], + }; + + return { + ...config, + kibana: { + ...config.kibana, + signals, + tooltips: { + centerOnMark: EVENT_TOOLTIP_CENTER_ON_MARK, + }, + }, + }; +}; + +// Get the first xaxis field as only 1 setup of X Axis will be supported and +// there won't be support for split series and split chart +export const getXAxisId = ( + dimensions: any, + columns: OpenSearchDashboardsDatatableColumn[] +): string => { + return columns.filter((column) => column.name === dimensions.x.label)[0].id; +}; + +export const isVisLayerColumn = (column: OpenSearchDashboardsDatatableColumn): boolean => { + return column.meta?.type === VIS_LAYER_COLUMN_TYPE; +}; + +/** + * For temporal domain ranges, there is a bug when passing timestamps in vega lite + * that is still present in the current libraries we are using when developing in a + * dev env. See https://github.com/vega/vega-lite/issues/6060 for bug details. + * So, we convert to a vega-lite Date Time object and pass that instead. + * See https://vega.github.io/vega-lite/docs/datetime.html for details on Date Time. + */ +const convertToDateTimeObj = (timestamp: number): any => { + const momentObj = moment(timestamp); + return { + year: Number(momentObj.format('YYYY')), + month: momentObj.format('MMMM'), + date: momentObj.date(), + hours: momentObj.hours(), + minutes: momentObj.minutes(), + seconds: momentObj.seconds(), + milliseconds: momentObj.milliseconds(), + }; +}; + +export const generateVisLayerFilterString = (visLayerColumnIds: string[]): string => { + if (!isEmpty(visLayerColumnIds)) { + const filterString = visLayerColumnIds.map( + (visLayerColumnId) => `datum['${visLayerColumnId}'] > 0` + ); + return filterString.join(' || '); + } else { + // if there is no VisLayers to display, then filter out everything by always returning false + return 'false'; + } +}; + +export const generateVisLayerTooltipFields = ( + visLayerColumnIds: string[] +): Array<{ field: string }> => { + return visLayerColumnIds.map((id) => { + return { + field: id, + }; + }); +}; + +/** + * By default, the source datatable will not include rows with empty data. + * For handling events that may belong in missing buckets that are not yet + * created, we need to create them. For more details, see description in + * https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3145 + * + * Note that this may add buckets with start/end times out of the chart bounds. + * This is the current default behavior of histogram aggregations with intervals, + * in order for the bucket keys to have "clean" timestamp keys (e.g., 1/1 @ 12AM). + * For more details, see + * https://opensearch.org/docs/latest/opensearch/bucket-agg/#histogram-date_histogram + * + * Also note this is only adding empty buckets at the beginning/end of a table. We are + * not taking into account missing buckets within source datapoints. Because of this + * limitation, it is possible that charted events may not be put into the most precise + * bucket based on their raw event timestamps, if there is missing / sparse source data. + */ +export const addMissingRowsToTableBounds = ( + datatable: OpenSearchDashboardsDatatable, + dimensions: any +): OpenSearchDashboardsDatatable => { + const augmentedTable = cloneDeep(datatable); + const intervalMillis = moment.duration(dimensions.x.params.interval).asMilliseconds(); + const xAxisId = getXAxisId(dimensions, augmentedTable.columns); + const chartStartTime = new Date(dimensions.x.params.bounds.min).valueOf(); + const chartEndTime = new Date(dimensions.x.params.bounds.max).valueOf(); + + if (!isEmpty(augmentedTable.rows)) { + const dataStartTime = augmentedTable.rows[0][xAxisId] as number; + const dataEndTime = augmentedTable.rows[augmentedTable.rows.length - 1][xAxisId] as number; + + let curStartTime = dataStartTime; + while (curStartTime > chartStartTime) { + curStartTime -= intervalMillis; + augmentedTable.rows.unshift({ + [xAxisId]: curStartTime, + }); + } + + let curEndTime = dataEndTime; + while (curEndTime < chartEndTime) { + curEndTime += intervalMillis; + augmentedTable.rows.push({ + [xAxisId]: curEndTime, + }); + } + } else { + // if there's no existing rows, create them all + let curTime = chartStartTime; + while (curTime <= chartEndTime) { + augmentedTable.rows.push({ + [xAxisId]: curTime, + }); + curTime += intervalMillis; + } + } + return augmentedTable; +}; + +/** + * Adding events into the correct x-axis key (the time bucket) + * based on the table. As of now only results from + * PointInTimeEventsVisLayers are supported + */ +export const addPointInTimeEventsLayersToTable = ( + datatable: OpenSearchDashboardsDatatable, + dimensions: any, + visLayers: PointInTimeEventsVisLayer[] +): OpenSearchDashboardsDatatable => { + const augmentedTable = addMissingRowsToTableBounds(datatable, dimensions); + const xAxisId = getXAxisId(dimensions, augmentedTable.columns); + + if (isEmpty(visLayers) || augmentedTable.rows.length === 0) return augmentedTable; + + // Create columns for every unique event type. This is so we can aggregate on the different event types + // (e.g., 'Anomalies', 'Alerts') + [ + ...new Set(visLayers.map((visLayer: PointInTimeEventsVisLayer) => visLayer.pluginEventType)), + ].forEach((pluginEventType: string) => { + augmentedTable.columns.push({ + id: pluginEventType, + name: `${pluginEventType} count`, + meta: { + type: VIS_LAYER_COLUMN_TYPE, + }, + }); + }); + + visLayers.forEach((visLayer: PointInTimeEventsVisLayer) => { + const visLayerColumnId = `${visLayer.pluginEventType}`; + + // Add placeholder values of 0 for every event value. This is so the tooltip + // can render correctly without showing the 'undefined' string + let row = 0; + while (row < augmentedTable.rows.length) { + augmentedTable.rows[row] = { + ...augmentedTable.rows[row], + [visLayerColumnId]: get(augmentedTable.rows[row], visLayerColumnId, 0) as number, + }; + row++; + } + + // if only one row / one datapoint, put all events into this bucket + if (augmentedTable.rows.length === 1) { + augmentedTable.rows[0] = { + ...augmentedTable.rows[0], + [visLayerColumnId]: + (get(augmentedTable.rows[0], visLayerColumnId, 0) as number) + visLayer.events.length, + }; + return; + } + + // Bin the timestamps to the closest x-axis key, adding + // an entry for this vis layer ID. Sorting the timestamps first + // so that we will only search a particular row value once. + // There could be some optimizations, such as binary search + dynamically + // changing the bounds, but performance benefits would be very minimal + // if any, given the upper bounds limit on n already due to chart constraints. + let rowIndex = 0; + const minVal = augmentedTable.rows[0][xAxisId] as number; + const maxVal = + (augmentedTable.rows[augmentedTable.rows.length - 1][xAxisId] as number) + + moment.duration(dimensions.x.params.interval).asMilliseconds(); + const sortedTimestamps = visLayer.events + .map((event: PointInTimeEvent) => event.timestamp) + .filter((timestamp: number) => timestamp >= minVal && timestamp <= maxVal) + .sort((n1: number, n2: number) => n1 - n2) as number[]; + + sortedTimestamps.forEach((timestamp) => { + while (rowIndex < augmentedTable.rows.length - 1) { + const smallerVal = augmentedTable.rows[rowIndex][xAxisId] as number; + const higherVal = augmentedTable.rows[rowIndex + 1][xAxisId] as number; + let rowIndexToInsert: number; + + // timestamp is on the left bounds of the chart + if (timestamp === smallerVal) { + rowIndexToInsert = rowIndex; + + // timestamp is in between the right 2 buckets. determine which one it is closer to + } else if (timestamp <= higherVal) { + const smallerValDiff = Math.abs(timestamp - smallerVal); + const higherValDiff = Math.abs(timestamp - higherVal); + rowIndexToInsert = smallerValDiff <= higherValDiff ? rowIndex : rowIndex + 1; + } + + // timestamp is on the right bounds of the chart + else if (rowIndex + 1 === augmentedTable.rows.length - 1) { + rowIndexToInsert = rowIndex + 1; + // timestamp is still too small; traverse to next bucket + } else { + rowIndex += 1; + continue; + } + + // inserting the value. increment if the mapping/property already exists + augmentedTable.rows[rowIndexToInsert][visLayerColumnId] = + (get(augmentedTable.rows[rowIndexToInsert], visLayerColumnId, 0) as number) + 1; + break; + } + }); + }); + return augmentedTable; +}; + +/** + * Updating the vega lite spec to include layers and marks related to + * PointInTimeEventsVisLayers. It is assumed the datatable has already been + * augmented with columns and row data containing the vis layers. + */ +export const addPointInTimeEventsLayersToSpec = ( + datatable: OpenSearchDashboardsDatatable, + dimensions: any, + spec: object +): object => { + const newSpec = cloneDeep(spec) as any; + + const xAxisId = getXAxisId(dimensions, datatable.columns); + const xAxisTitle = dimensions.x.label.replaceAll('"', ''); + const bucketStartTime = convertToDateTimeObj(datatable.rows[0][xAxisId] as number); + const bucketEndTime = convertToDateTimeObj( + datatable.rows[datatable.rows.length - 1][xAxisId] as number + ); + const visLayerColumns = datatable.columns.filter((column: OpenSearchDashboardsDatatableColumn) => + isVisLayerColumn(column) + ); + const visLayerColumnIds = visLayerColumns.map((column) => column.id); + + // Hide x axes text on existing chart so they are only visible on the event chart + newSpec.layer.forEach((dataSeries: any) => { + if (get(dataSeries, 'encoding.x.axis', null) !== null) { + dataSeries.encoding.x.axis = { + ...dataSeries.encoding.x.axis, + labels: false, + title: null, + }; + } + }); + + // Add a rule to the existing layer for showing lines on the chart if a dot is hovered on + newSpec.layer.push({ + mark: { + type: 'rule', + color: EVENT_COLOR, + opacity: 1, + }, + transform: [{ filter: generateVisLayerFilterString(visLayerColumnIds) }], + encoding: { + x: { + field: xAxisId, + type: 'temporal', + }, + opacity: { + value: 0, + condition: { empty: false, param: HOVER_PARAM, value: 1 }, + }, + }, + }); + + // Nesting layer into a vconcat field so we can append event chart. + newSpec.vconcat = [] as any[]; + newSpec.vconcat.push({ + layer: newSpec.layer, + }); + delete newSpec.layer; + + // Adding the event timeline chart + newSpec.vconcat.push({ + height: EVENT_TIMELINE_HEIGHT, + mark: { + type: 'point', + shape: EVENT_MARK_SHAPE, + fill: EVENT_COLOR, + stroke: EVENT_COLOR, + strokeOpacity: 1, + fillOpacity: 1, + // This style is only used to locate this mark when trying to add signals in the compiled vega spec. + // @see @method vega_parser._compileVegaLite + style: [`${VisAnnotationType.POINT_IN_TIME_ANNOTATION}`], + tooltip: true, + }, + transform: [ + { filter: generateVisLayerFilterString(visLayerColumnIds) }, + { calculate: `'${VisAnnotationType.POINT_IN_TIME_ANNOTATION}'`, as: 'annotationType' }, + ], + params: [{ name: HOVER_PARAM, select: { type: 'point', on: 'mouseover' } }], + encoding: { + x: { + axis: { + title: xAxisTitle, + grid: false, + ticks: true, + orient: 'bottom', + domain: true, + }, + field: xAxisId, + type: 'temporal', + scale: { + domain: [bucketStartTime, bucketEndTime], + }, + }, + size: { + condition: { empty: false, param: HOVER_PARAM, value: EVENT_MARK_SIZE_ENLARGED }, + value: EVENT_MARK_SIZE, + }, + tooltip: generateVisLayerTooltipFields(visLayerColumnIds), + }, + }); + + return newSpec; +}; + +// This is the total y-axis padding such that if this is added to the "padding" value of the view, if there is no axis, +// it will align values on the x-axis +export const calculateYAxisPadding = (config: YAxisConfig): number => { + // TODO: figure out where this value is coming from + const defaultPadding = 3; + return ( + get(config, 'minExtent', 0) + + get(config, 'offset', 0) + + get(config, 'translate', 0) + + get(config, 'domainWidth', 0) + + get(config, 'labelPadding', 0) + + get(config, 'titlePadding', 0) + + get(config, 'tickOffset', 0) + + get(config, 'tickSize', 0) + + defaultPadding + ); +}; + +// Parse the vis augmenter config to apply different visual changes to the event chart spec. +// This includes potentially removing the original vis data, hiding axes, moving the legend, etc. +// Primarily used within the view events flyout to render the charts in different ways, and to +// ensure the stacked event charts are aligned with the base vis chart. +export const augmentEventChartSpec = ( + config: VisAugmenterEmbeddableConfig, + origSpec: object +): {} => { + const inFlyout = get(config, 'inFlyout', false) as boolean; + const flyoutContext = get(config, 'flyoutContext', VisFlyoutContext.BASE_VIS); + + const newVconcat = [] as Array<{}>; + // @ts-ignore + const newConfig = origSpec?.config; + const visChart = get(origSpec, 'vconcat[0]', {}); + const eventChart = get(origSpec, 'vconcat[1]', {}); + + if (inFlyout) { + switch (flyoutContext) { + case VisFlyoutContext.BASE_VIS: + newConfig.legend = { + ...newConfig.legend, + orient: 'top', + // need to set offset to 0 so we don't cut off the chart canvas within the embeddable + offset: 0, + }; + break; + + case VisFlyoutContext.EVENT_VIS: + eventChart.encoding.x.axis = { + domain: true, + grid: false, + ticks: false, + labels: false, + title: null, + }; + eventChart.mark.fillOpacity = 0; + break; + + case VisFlyoutContext.TIMELINE_VIS: + eventChart.transform = [ + { + filter: 'false', + }, + ]; + break; + } + + // if coming from view events page, need to standardize the y axis padding values so we can + // align all of the charts correctly + newConfig.axisY = { + // We need minExtent and maxExtent to be the same. We cannot calculate these on-the-fly + // so we need to force a static value. We choose 40 as a good middleground for sufficient + // axis space without taking up too much actual chart space. + minExtent: 40, + maxExtent: 40, + offset: 0, + translate: 0, + domainWidth: 1, + labelPadding: 2, + titlePadding: 2, + tickOffset: 0, + tickSize: 5, + } as YAxisConfig; + } + + if (flyoutContext === VisFlyoutContext.BASE_VIS) { + newVconcat.push(visChart); + } + newVconcat.push(eventChart); + + return { + ...cloneDeep(origSpec), + config: newConfig, + vconcat: newVconcat, + }; +}; diff --git a/src/plugins/vis_augmenter/public/vega/index.ts b/src/plugins/vis_augmenter/public/vega/index.ts new file mode 100644 index 000000000000..0e8ad44d2bd7 --- /dev/null +++ b/src/plugins/vis_augmenter/public/vega/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './helpers'; diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/README.md b/src/plugins/vis_augmenter/public/view_events_flyout/README.md new file mode 100644 index 000000000000..1f4e07b6b84f --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/README.md @@ -0,0 +1,14 @@ +## View Events Flyout + +### Overview + +This flyout provides a detailed view of all `VisLayer`s associated to a particular visualization. It consists of two main portions: + +1. The top portion showing the base visualization, and the contextual time range that can be refreshed to fetch any new data in real time +2. The bottom portion showing a breakdown of each `VisLayer`, organized first by origin plugin (e.g., "Anomaly Detection"), and then by each plugin resource (e.g., "Anomaly Detector"). Each chart represents results produced from a single plugin resource. The resource name will also be a link, directing the user to the resource's details page within its respective plugin. + +### Improvements + +Currently, the charts rendered within this flyout are utilizing the `embeddables` plugin to re-create the source visualization, as well as data filtering and other visual changes, based on what is being rendered. Ideally, this can be decoupled from `embeddables` entirely, and the charts can all be rendered directly using expression renderers. This can help clean up and remove dependencies across plugins, as well as being able to remove the `VisAugmenterEmbeddableConfig` that has been added to `VisualizeEmbeddable` in order to persist some of the needed visual changes to the charts. + +For more details on this, see the [GitHub issue](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4483). diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/actions/index.ts b/src/plugins/vis_augmenter/public/view_events_flyout/actions/index.ts new file mode 100644 index 000000000000..cd333ed9451d --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/actions/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { OPEN_EVENTS_FLYOUT_ACTION, OpenEventsFlyoutAction } from './open_events_flyout_action'; +export { VIEW_EVENTS_OPTION_ACTION, ViewEventsOptionAction } from './view_events_option_action'; diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout.tsx new file mode 100644 index 000000000000..c9f6d75e1190 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout.tsx @@ -0,0 +1,34 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import React from 'react'; +import { toMountPoint } from '../../../../opensearch_dashboards_react/public'; +import { ViewEventsFlyout } from '../components'; +import { VIEW_EVENTS_FLYOUT_STATE, setFlyoutState } from '../flyout_state'; +import { getCore } from '../../services'; + +interface Props { + savedObjectId: string; +} + +export async function openViewEventsFlyout(props: Props) { + setFlyoutState(VIEW_EVENTS_FLYOUT_STATE.OPEN); + const flyoutSession = getCore().overlays.openFlyout( + toMountPoint( + { + if (flyoutSession) { + flyoutSession.close(); + setFlyoutState(VIEW_EVENTS_FLYOUT_STATE.CLOSED); + } + }} + savedObjectId={props.savedObjectId} + /> + ), + { + 'data-test-subj': 'viewEventsFlyout', + ownFocus: true, + } + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout_action.test.ts b/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout_action.test.ts new file mode 100644 index 000000000000..e6cb654ab422 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout_action.test.ts @@ -0,0 +1,106 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { OpenEventsFlyoutAction } from './open_events_flyout_action'; +import flyoutStateModule from '../flyout_state'; +import servicesModule from '../../services'; + +// Mocking the flyout state service. Defaulting to CLOSED. May override +// getFlyoutState() in below individual tests to test out different scenarios. +jest.mock('src/plugins/vis_augmenter/public/view_events_flyout/flyout_state', () => { + return { + VIEW_EVENTS_FLYOUT_STATE: { + OPEN: 'OPEN', + CLOSED: 'CLOSED', + }, + getFlyoutState: () => 'CLOSED', + setFlyoutState: () => {}, + }; +}); + +// Mocking core service as needed when making calls to the core's overlays service +jest.mock('src/plugins/vis_augmenter/public/services.ts', () => { + return { + getCore: () => { + return { + overlays: { + openFlyout: () => {}, + }, + }; + }, + }; +}); + +afterEach(async () => { + jest.clearAllMocks(); +}); + +describe('OpenEventsFlyoutAction', () => { + it('is incompatible with null saved obj id', async () => { + const action = new OpenEventsFlyoutAction(); + const savedObjectId = null; + // @ts-ignore + expect(await action.isCompatible({ savedObjectId })).toBe(false); + }); + + it('is incompatible with undefined saved obj id', async () => { + const action = new OpenEventsFlyoutAction(); + const savedObjectId = undefined; + // @ts-ignore + expect(await action.isCompatible({ savedObjectId })).toBe(false); + }); + + it('is incompatible with empty saved obj id', async () => { + const action = new OpenEventsFlyoutAction(); + const savedObjectId = ''; + expect(await action.isCompatible({ savedObjectId })).toBe(false); + }); + + it('execute throws error if incompatible saved obj id', async () => { + const action = new OpenEventsFlyoutAction(); + async function check(id: any) { + await action.execute({ savedObjectId: id }); + } + await expect(check(null)).rejects.toThrow(Error); + await expect(check(undefined)).rejects.toThrow(Error); + await expect(check('')).rejects.toThrow(Error); + }); + + it('execute calls openFlyout if compatible saved obj id and flyout is closed', async () => { + const getFlyoutStateSpy = jest + .spyOn(flyoutStateModule, 'getFlyoutState') + .mockImplementation(() => 'CLOSED'); + // openFlyout exists within core.overlays service. We spy on the initial getCore() fn call indicating + // that openFlyout is getting called. + const openFlyoutStateSpy = jest.spyOn(servicesModule, 'getCore'); + const savedObjectId = 'test-id'; + const action = new OpenEventsFlyoutAction(); + await action.execute({ savedObjectId }); + expect(openFlyoutStateSpy).toHaveBeenCalledTimes(1); + expect(getFlyoutStateSpy).toHaveBeenCalledTimes(1); + }); + + it('execute does not call openFlyout if compatible saved obj id and flyout is open', async () => { + const getFlyoutStateSpy = jest + .spyOn(flyoutStateModule, 'getFlyoutState') + .mockImplementation(() => 'OPEN'); + const openFlyoutStateSpy = jest.spyOn(servicesModule, 'getCore'); + const savedObjectId = 'test-id'; + const action = new OpenEventsFlyoutAction(); + await action.execute({ savedObjectId }); + expect(openFlyoutStateSpy).toHaveBeenCalledTimes(0); + expect(getFlyoutStateSpy).toHaveBeenCalledTimes(1); + }); + + it('Returns display name', async () => { + const action = new OpenEventsFlyoutAction(); + expect(action.getDisplayName()).toBeDefined(); + }); + + it('Returns undefined icon type', async () => { + const action = new OpenEventsFlyoutAction(); + expect(action.getIconType()).toBeUndefined(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout_action.ts b/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout_action.ts new file mode 100644 index 000000000000..cb47e5d6a85c --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/actions/open_events_flyout_action.ts @@ -0,0 +1,60 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { Action, IncompatibleActionError } from '../../../../ui_actions/public'; +import { AugmentVisContext } from '../../ui_actions_bootstrap'; +import { openViewEventsFlyout } from './open_events_flyout'; +import { VIEW_EVENTS_FLYOUT_STATE, getFlyoutState } from '../flyout_state'; + +export const OPEN_EVENTS_FLYOUT_ACTION = 'OPEN_EVENTS_FLYOUT_ACTION'; + +/** + * This action is identical to VIEW_EVENTS_OPTION_ACTION, but with different context. + * This is because the chart doesn't persist the embeddable, which is the default + * context used by the CONTEXT_MENU_TRIGGER. Because of that, we need a separate + * one that can be persisted in the chart - in this case, the AugmentVisContext, + * which is just a saved object ID. + */ + +export class OpenEventsFlyoutAction implements Action { + public readonly type = OPEN_EVENTS_FLYOUT_ACTION; + public readonly id = OPEN_EVENTS_FLYOUT_ACTION; + public order = 1; + + constructor() {} + + public getIconType() { + return undefined; + } + + public getDisplayName() { + return i18n.translate('dashboard.actions.viewEvents.displayName', { + defaultMessage: 'View Events', + }); + } + + public async isCompatible({ savedObjectId }: AugmentVisContext) { + // checks for null / undefined / empty string + return savedObjectId ? true : false; + } + + public async execute({ savedObjectId }: AugmentVisContext) { + if (!(await this.isCompatible({ savedObjectId }))) { + throw new IncompatibleActionError(); + } + + // This action may get triggered even when the flyout is already open (e.g., + // clicking on an annotation point within a chart displayed in the flyout). + // In such case, we want to ignore it such that users can't keep endlessly + // re-opening it. + if (getFlyoutState() === VIEW_EVENTS_FLYOUT_STATE.CLOSED) { + openViewEventsFlyout({ + savedObjectId, + }); + } + } +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/actions/view_events_option_action.test.ts b/src/plugins/vis_augmenter/public/view_events_flyout/actions/view_events_option_action.test.ts new file mode 100644 index 000000000000..cabca0f0dcd7 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/actions/view_events_option_action.test.ts @@ -0,0 +1,137 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ViewEventsOptionAction } from './view_events_option_action'; +import { createMockErrorEmbeddable, createMockVisEmbeddable } from '../../mocks'; +import flyoutStateModule from '../flyout_state'; +import servicesModule from '../../services'; + +// Mocking the flyout state service. Defaulting to CLOSED. May override +// getFlyoutState() in below individual tests to test out different scenarios. +jest.mock('src/plugins/vis_augmenter/public/view_events_flyout/flyout_state', () => { + return { + VIEW_EVENTS_FLYOUT_STATE: { + OPEN: 'OPEN', + CLOSED: 'CLOSED', + }, + getFlyoutState: () => 'CLOSED', + setFlyoutState: () => {}, + }; +}); + +// Mocking the UISettings service. This is needed when making eligibility checks for the actions, +// which does UISettings checks to ensure the feature is enabled. +// Also mocking core service as needed when making calls to the core's overlays service +jest.mock('src/plugins/vis_augmenter/public/services.ts', () => { + return { + getUISettings: () => { + return { + get: (config: string) => { + switch (config) { + case 'visualization:enablePluginAugmentation': + return true; + case 'visualization:enablePluginAugmentation.maxPluginObjects': + return 10; + default: + throw new Error(`Accessing ${config} is not supported in the mock.`); + } + }, + }; + }, + getCore: () => { + return { + overlays: { + openFlyout: () => {}, + }, + }; + }, + getSavedAugmentVisLoader: () => { + return { + delete: () => {}, + findAll: () => { + return { + hits: [], + }; + }, + }; + }, + }; +}); + +afterEach(async () => { + jest.clearAllMocks(); +}); + +describe('ViewEventsOptionAction', () => { + it('is incompatible with ErrorEmbeddables', async () => { + const action = new ViewEventsOptionAction(); + const errorEmbeddable = createMockErrorEmbeddable(); + expect(await action.isCompatible({ embeddable: errorEmbeddable })).toBe(false); + }); + + it('is incompatible with VisualizeEmbeddable with invalid vis', async () => { + const visEmbeddable = createMockVisEmbeddable('test-saved-obj-id', 'test-title', false); + const action = new ViewEventsOptionAction(); + expect(await action.isCompatible({ embeddable: visEmbeddable })).toBe(false); + }); + + it('is incompatible with VisualizeEmbeddable with valid vis and no vislayers', async () => { + const visEmbeddable = createMockVisEmbeddable('test-saved-obj-id', 'test-title'); + visEmbeddable.visLayers = []; + const action = new ViewEventsOptionAction(); + expect(await action.isCompatible({ embeddable: visEmbeddable })).toBe(false); + }); + + it('is compatible with VisualizeEmbeddable with valid vis', async () => { + const visEmbeddable = createMockVisEmbeddable('test-saved-obj-id', 'test-title'); + const action = new ViewEventsOptionAction(); + expect(await action.isCompatible({ embeddable: visEmbeddable })).toBe(true); + }); + + it('execute throws error if incompatible embeddable', async () => { + const errorEmbeddable = createMockErrorEmbeddable(); + const action = new ViewEventsOptionAction(); + async function check() { + await action.execute({ embeddable: errorEmbeddable }); + } + await expect(check()).rejects.toThrow(Error); + }); + + it('execute calls openFlyout if compatible embeddable and flyout is currently closed', async () => { + const getFlyoutStateSpy = jest + .spyOn(flyoutStateModule, 'getFlyoutState') + .mockImplementation(() => 'CLOSED'); + // openFlyout exists within core.overlays service. We spy on the initial getCore() fn call indicating + // that openFlyout is getting called. + const openFlyoutStateSpy = jest.spyOn(servicesModule, 'getCore'); + const visEmbeddable = createMockVisEmbeddable('test-saved-obj-id', 'test-title'); + const action = new ViewEventsOptionAction(); + await action.execute({ embeddable: visEmbeddable }); + expect(openFlyoutStateSpy).toHaveBeenCalledTimes(1); + expect(getFlyoutStateSpy).toHaveBeenCalledTimes(1); + }); + + it('execute does not call openFlyout if compatible embeddable and flyout is currently open', async () => { + const getFlyoutStateSpy = jest + .spyOn(flyoutStateModule, 'getFlyoutState') + .mockImplementation(() => 'OPEN'); + const openFlyoutStateSpy = jest.spyOn(servicesModule, 'getCore'); + const visEmbeddable = createMockVisEmbeddable('test-saved-obj-id', 'test-title'); + const action = new ViewEventsOptionAction(); + await action.execute({ embeddable: visEmbeddable }); + expect(openFlyoutStateSpy).toHaveBeenCalledTimes(0); + expect(getFlyoutStateSpy).toHaveBeenCalledTimes(1); + }); + + it('Returns display name', async () => { + const action = new ViewEventsOptionAction(); + expect(action.getDisplayName()).toBeDefined(); + }); + + it('Returns an icon type', async () => { + const action = new ViewEventsOptionAction(); + expect(action.getIconType()).toBeDefined(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/actions/view_events_option_action.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/actions/view_events_option_action.tsx new file mode 100644 index 000000000000..6410e8a13634 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/actions/view_events_option_action.tsx @@ -0,0 +1,72 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; +import { get, isEmpty } from 'lodash'; +import { VisualizeEmbeddable } from '../../../../visualizations/public'; +import { EmbeddableContext } from '../../../../embeddable/public'; +import { Action, IncompatibleActionError } from '../../../../ui_actions/public'; +import { openViewEventsFlyout } from './open_events_flyout'; +import { isEligibleForVisLayers } from '../../utils'; +import { VIEW_EVENTS_FLYOUT_STATE, getFlyoutState } from '../flyout_state'; + +export const VIEW_EVENTS_OPTION_ACTION = 'VIEW_EVENTS_OPTION_ACTION'; + +export class ViewEventsOptionAction implements Action { + public readonly type = VIEW_EVENTS_OPTION_ACTION; + public readonly id = VIEW_EVENTS_OPTION_ACTION; + public order = 1; + + public grouping: Action['grouping'] = [ + { + id: VIEW_EVENTS_OPTION_ACTION, + getDisplayName: this.getDisplayName, + getIconType: this.getIconType, + category: 'vis_augmenter', + order: 10, + }, + ]; + + constructor() {} + + public getIconType(): EuiIconType { + return 'inspect'; + } + + public getDisplayName() { + return i18n.translate('dashboard.actions.viewEvents.displayName', { + defaultMessage: 'View Events', + }); + } + + public async isCompatible({ embeddable }: EmbeddableContext) { + const vis = (embeddable as VisualizeEmbeddable).vis; + return ( + vis !== undefined && + isEligibleForVisLayers(vis) && + !isEmpty((embeddable as VisualizeEmbeddable).visLayers) + ); + } + + public async execute({ embeddable }: EmbeddableContext) { + if (!(await this.isCompatible({ embeddable }))) { + throw new IncompatibleActionError(); + } + + const visEmbeddable = embeddable as VisualizeEmbeddable; + const savedObjectId = get(visEmbeddable.getInput(), 'savedObjectId', ''); + + // This action may get triggered even when the flyout is already open (e.g., + // clicking on an annotation point within a chart displayed in the flyout). + // In such case, we want to ignore it such that users can't keep endlessly + // re-opening it. + if (getFlyoutState() === VIEW_EVENTS_FLYOUT_STATE.CLOSED) { + openViewEventsFlyout({ + savedObjectId, + }); + } + } +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/__snapshots__/error_flyout_body.test.tsx.snap b/src/plugins/vis_augmenter/public/view_events_flyout/components/__snapshots__/error_flyout_body.test.tsx.snap new file mode 100644 index 000000000000..7094a4660dbd --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/__snapshots__/error_flyout_body.test.tsx.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders component 1`] = ` +
+
+
+
+
+
+
+
+
+ oh no an error! +
+
+
+
+
+
+
+
+
+`; diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/__snapshots__/loading_flyout_body.test.tsx.snap b/src/plugins/vis_augmenter/public/view_events_flyout/components/__snapshots__/loading_flyout_body.test.tsx.snap new file mode 100644 index 000000000000..6b642518fc6e --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/__snapshots__/loading_flyout_body.test.tsx.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders component 1`] = ` +
+
+
+
+
+
+ +
+
+
+
+
+
+`; diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/base_vis_item.test.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/base_vis_item.test.tsx new file mode 100644 index 000000000000..ca88941f6f23 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/base_vis_item.test.tsx @@ -0,0 +1,33 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { BaseVisItem } from './base_vis_item'; +import { createMockVisEmbeddable } from '../../mocks'; + +jest.mock('../../services', () => { + return { + getEmbeddable: () => { + return { + getEmbeddablePanel: () => { + return 'MockEmbeddablePanel'; + }, + }; + }, + }; +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('', () => { + it('renders', async () => { + const embeddable = createMockVisEmbeddable(); + const { getByTestId } = render(); + expect(getByTestId('baseVis')).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/base_vis_item.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/base_vis_item.tsx new file mode 100644 index 000000000000..3840c5a1f23b --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/base_vis_item.tsx @@ -0,0 +1,32 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { getEmbeddable } from '../../services'; +import { VisualizeEmbeddable } from '../../../../visualizations/public'; +import './styles.scss'; + +interface Props { + embeddable: VisualizeEmbeddable; +} + +export function BaseVisItem(props: Props) { + const PanelComponent = getEmbeddable().getEmbeddablePanel(); + + return ( + + + + + + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/date_range_item.test.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/date_range_item.test.tsx new file mode 100644 index 000000000000..bd07e115d158 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/date_range_item.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { findTestSubject } from 'test_utils/helpers'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { DateRangeItem } from './date_range_item'; +import { TimeRange } from '../../../../data/common'; +import { prettyDuration } from '@elastic/eui'; +import { DATE_RANGE_FORMAT } from './view_events_flyout'; + +describe('', () => { + const mockTimeRange = { + from: 'now-7d', + to: 'now', + } as TimeRange; + const mockReloadFn = jest.fn(); + + it('time range is displayed correctly', async () => { + const prettyTimeRange = prettyDuration( + mockTimeRange.from, + mockTimeRange.to, + [], + DATE_RANGE_FORMAT + ); + + const { getByText } = render(); + expect(getByText(prettyTimeRange)).toBeInTheDocument(); + }); + + it('triggers reload on clicking on refresh button', async () => { + const component = mountWithIntl( + + ); + const refreshButton = findTestSubject(component, 'refreshButton'); + refreshButton.simulate('click'); + expect(mockReloadFn).toHaveBeenCalledTimes(1); + }); + + // Note we are not creating/comparing snapshots for this component. That is because + // it will hardcode a time-specific value which can cause failures when running + // in different envs + it('renders component', async () => { + const { getByTestId } = render( + + ); + expect(getByTestId('durationText')).toBeInTheDocument(); + expect(getByTestId('refreshButton')).toBeInTheDocument(); + expect(getByTestId('refreshDescriptionText')).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/date_range_item.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/date_range_item.tsx new file mode 100644 index 000000000000..e2a7092f1e5f --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/date_range_item.tsx @@ -0,0 +1,65 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import moment from 'moment'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiIcon, + prettyDuration, + EuiButton, +} from '@elastic/eui'; +import { TimeRange } from '../../../../data/common'; +import { DATE_RANGE_FORMAT } from './view_events_flyout'; + +interface Props { + timeRange: TimeRange; + reload: () => void; +} + +export function DateRangeItem(props: Props) { + const [lastUpdatedTime, setLastUpdatedTime] = useState( + moment(Date.now()).format(DATE_RANGE_FORMAT) + ); + + const durationText = prettyDuration( + props.timeRange.from, + props.timeRange.to, + [], + DATE_RANGE_FORMAT + ); + + return ( + + + + + + {durationText} + + + { + props.reload(); + setLastUpdatedTime(moment(Date.now()).format(DATE_RANGE_FORMAT)); + }} + data-test-subj="refreshButton" + > + Refresh + + + + + {`This view is not updated to load the latest events automatically. + Last updated: ${lastUpdatedTime}`} + + + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/error_flyout_body.test.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/error_flyout_body.test.tsx new file mode 100644 index 000000000000..d3bb447ae934 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/error_flyout_body.test.tsx @@ -0,0 +1,21 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { ErrorFlyoutBody } from './error_flyout_body'; + +describe('', () => { + const errorMsg = 'oh no an error!'; + it('shows error message', async () => { + const { getByText } = render(); + expect(getByText(errorMsg)).toBeInTheDocument(); + }); + it('renders component', async () => { + const { container, getByTestId } = render(); + expect(getByTestId('errorCallOut')).toBeInTheDocument(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/error_flyout_body.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/error_flyout_body.tsx new file mode 100644 index 000000000000..1e0349aa18c2 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/error_flyout_body.tsx @@ -0,0 +1,25 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiFlyoutBody, EuiFlexGroup, EuiFlexItem, EuiCallOut } from '@elastic/eui'; + +interface Props { + errorMessage: string; +} + +export function ErrorFlyoutBody(props: Props) { + return ( + + + + + {props.errorMessage} + + + + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item.test.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item.test.tsx new file mode 100644 index 000000000000..99a865a9218c --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item.test.tsx @@ -0,0 +1,63 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { EventVisItem } from './event_vis_item'; +import { + createMockEventVisEmbeddableItem, + createMockVisEmbeddable, + createPluginResource, + createPointInTimeEventsVisLayer, +} from '../../mocks'; + +jest.mock('../../services', () => { + return { + getEmbeddable: () => { + return { + getEmbeddablePanel: () => { + return 'MockEmbeddablePanel'; + }, + }; + }, + getCore: () => { + return { + http: { + basePath: { + prepend: jest.fn(), + }, + }, + }; + }, + }; +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('', () => { + it('renders', async () => { + const item = createMockEventVisEmbeddableItem(); + const { getByTestId, getByText } = render(); + expect(getByTestId('eventVis')).toBeInTheDocument(); + expect(getByTestId('pluginResourceDescription')).toBeInTheDocument(); + expect(getByText(item.visLayer.pluginResource.name)).toBeInTheDocument(); + }); + + it('shows event count when rendering a PointInTimeEventsVisLayer', async () => { + const eventCount = 5; + const pluginResource = createPluginResource(); + const visLayer = createPointInTimeEventsVisLayer('test-plugin', pluginResource, eventCount); + const embeddable = createMockVisEmbeddable(); + const item = { + visLayer, + embeddable, + }; + const { getByTestId, getByText } = render(); + expect(getByTestId('eventCount')).toBeInTheDocument(); + expect(getByText(eventCount)).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item.tsx new file mode 100644 index 000000000000..cc00610c4a33 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item.tsx @@ -0,0 +1,53 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { get } from 'lodash'; +import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; +import { getEmbeddable, getCore } from '../../services'; +import './styles.scss'; +import { EventVisEmbeddableItem } from '.'; +import { EventVisItemIcon } from './event_vis_item_icon'; + +interface Props { + item: EventVisEmbeddableItem; +} + +export function EventVisItem(props: Props) { + const PanelComponent = getEmbeddable().getEmbeddablePanel(); + const baseUrl = getCore().http.basePath; + + const name = get(props, 'item.visLayer.pluginResource.name', ''); + const urlPath = get(props, 'item.visLayer.pluginResource.urlPath', ''); + + return ( + <> + + + + + + {name} + + + + + + + + + + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item_icon.test.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item_icon.test.tsx new file mode 100644 index 000000000000..5ae91d4fa1e0 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item_icon.test.tsx @@ -0,0 +1,51 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { findTestSubject } from 'test_utils/helpers'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { EventVisItemIcon } from './event_vis_item_icon'; +import { EuiPopover } from '@elastic/eui'; +import { createPluginResource, createPointInTimeEventsVisLayer } from '../../mocks'; + +describe('', () => { + it('shows event count when rendering a PointInTimeEventsVisLayer', async () => { + const eventCount = 5; + const pluginResource = createPluginResource(); + const visLayer = createPointInTimeEventsVisLayer('test-plugin', pluginResource, eventCount); + const { getByTestId, getByText } = render(); + expect(getByTestId('eventCount')).toBeInTheDocument(); + expect(getByText(eventCount)).toBeInTheDocument(); + }); + it('shows error when rendering a PointInTimeEventsVisLayer with an error', async () => { + const eventCount = 5; + const pluginResource = createPluginResource(); + const visLayerWithError = createPointInTimeEventsVisLayer( + 'test-plugin', + pluginResource, + eventCount, + true + ); + const { getByTestId } = render(); + expect(getByTestId('errorButton')).toBeInTheDocument(); + }); + it('triggers popout with error message when clicking on error button', async () => { + const eventCount = 5; + const pluginResource = createPluginResource(); + const visLayerWithError = createPointInTimeEventsVisLayer( + 'test-plugin', + pluginResource, + eventCount, + true, + 'some-error-message' + ); + const component = mountWithIntl(); + const errorButton = findTestSubject(component, 'dangerButton'); + errorButton.simulate('click'); + expect(component.find(EuiPopover).prop('isOpen')).toBe(true); + expect(component.contains('some-error-message')).toBe(true); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item_icon.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item_icon.tsx new file mode 100644 index 000000000000..8c00b72b85c8 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/event_vis_item_icon.tsx @@ -0,0 +1,63 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { get } from 'lodash'; +import { EuiFlexItem, EuiNotificationBadge, EuiButtonIcon, EuiPopover } from '@elastic/eui'; +import './styles.scss'; +import { VisLayer, VisLayerTypes } from '../../'; + +interface Props { + visLayer: VisLayer; +} + +/** + * Returns a badge with the event count for this particular VisLayer (only PointInTimeEventVisLayers + * are currently supported), or an error icon which can be clicked to view the error message. + */ +export function EventVisItemIcon(props: Props) { + const [isErrorPopoverOpen, setIsErrorPopoverOpen] = useState(false); + const onButtonClick = () => setIsErrorPopoverOpen((isOpen) => !isOpen); + const closeErrorPopover = () => setIsErrorPopoverOpen(false); + + const errorMsg = get(props, 'visLayer.error.message', undefined) as string | undefined; + const isError = errorMsg !== undefined; + const showEventCount = props.visLayer.type === VisLayerTypes.PointInTimeEvents && !isError; + + const dangerButton = ( + + ); + + return ( + <> + {showEventCount ? ( + + + {get(props.visLayer, 'events.length', 0)} + + + ) : isError ? ( + + +
{errorMsg}
+
+
+ ) : null} + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/events_panel.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/events_panel.tsx new file mode 100644 index 000000000000..33f3ea8bb205 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/events_panel.tsx @@ -0,0 +1,32 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import './styles.scss'; +import { EventVisEmbeddableItem, EventVisEmbeddablesMap } from '.'; +import { PluginEventsPanel } from './plugin_events_panel'; + +interface Props { + eventVisEmbeddablesMap: EventVisEmbeddablesMap; +} + +export function EventsPanel(props: Props) { + return ( + <> + {Array.from(props.eventVisEmbeddablesMap.keys()).map((key, index) => { + return ( +
+ {index !== 0 ? : null} + +
+ ); + })} + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/index.ts b/src/plugins/vis_augmenter/public/view_events_flyout/components/index.ts new file mode 100644 index 000000000000..70564145711c --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { ViewEventsFlyout } from './view_events_flyout'; +export { EventVisEmbeddablesMap, EventVisEmbeddableItem } from './types'; +export { fetchVisEmbeddable } from './utils'; diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/loading_flyout_body.test.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/loading_flyout_body.test.tsx new file mode 100644 index 000000000000..0a06516831d5 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/loading_flyout_body.test.tsx @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { LoadingFlyoutBody } from './loading_flyout_body'; + +describe('', () => { + it('renders component', async () => { + const { container, getByTestId } = render(); + expect(getByTestId('loadingSpinner')).toBeInTheDocument(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/loading_flyout_body.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/loading_flyout_body.tsx new file mode 100644 index 000000000000..90a6d5213029 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/loading_flyout_body.tsx @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiFlyoutBody, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; + +export function LoadingFlyoutBody() { + return ( + + + + + + + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/plugin_events_panel.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/plugin_events_panel.tsx new file mode 100644 index 000000000000..0f737f2c058b --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/plugin_events_panel.tsx @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiFlexItem, EuiText } from '@elastic/eui'; +import './styles.scss'; +import { EventVisItem } from './event_vis_item'; +import { EventVisEmbeddableItem } from '.'; + +interface Props { + pluginTitle: string; + items: EventVisEmbeddableItem[]; +} + +export function PluginEventsPanel(props: Props) { + return ( + <> + + + {props.pluginTitle} + + + + {props.items.map((item, index) => ( + + ))} + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/styles.scss b/src/plugins/vis_augmenter/public/view_events_flyout/components/styles.scss new file mode 100644 index 000000000000..75cb154d1957 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/styles.scss @@ -0,0 +1,60 @@ +$vis-description-width: 200px; +$event-vis-height: 55px; +$timeline-panel-height: 90px; +$content-padding-top: 110px; // Padding needed within view events flyout content to sit comfortably below flyout header +$date-range-height: 45px; // Static height we want for the date range picker component +$error-icon-padding-right: -8px; // This is so the error icon is aligned consistent with the event count icons +$base-vis-min-height: 25vh; // Visualizations require the container to have a valid width and height to render + +.view-events-flyout { + &__baseVis { + min-height: $base-vis-min-height; + } + + &__eventVis { + height: $event-vis-height; + } + + &__timelinePanel { + height: $timeline-panel-height; + } + + &__visDescription { + min-width: $vis-description-width; + max-width: $vis-description-width; + word-break: break-word; + } + + &__content { + position: absolute; + top: $content-padding-top; + right: $euiSizeM; + bottom: $euiSizeM; + left: $euiSizeM; + } + + &__contentPanel { + @include euiYScroll; + + overflow: auto; + overflow-x: hidden; + overflow-y: hidden; + scrollbar-gutter: stable both-edges; + } +} + +.show-y-scroll { + overflow-y: scroll; +} + +.date-range-panel-height { + height: $date-range-height; +} + +.timeline-panel-height { + height: $timeline-panel-height; +} + +.error-icon-padding { + margin-right: $error-icon-padding-right; +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/timeline_panel.test.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/timeline_panel.test.tsx new file mode 100644 index 000000000000..a22ac5aa209c --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/timeline_panel.test.tsx @@ -0,0 +1,33 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { TimelinePanel } from './timeline_panel'; +import { createMockVisEmbeddable } from '../../mocks'; + +jest.mock('../../services', () => { + return { + getEmbeddable: () => { + return { + getEmbeddablePanel: () => { + return 'MockEmbeddablePanel'; + }, + }; + }, + }; +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('', () => { + it('renders', async () => { + const embeddable = createMockVisEmbeddable(); + const { getByTestId } = render(); + expect(getByTestId('timelineVis')).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/timeline_panel.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/timeline_panel.tsx new file mode 100644 index 000000000000..6507eac8cc23 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/timeline_panel.tsx @@ -0,0 +1,35 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { getEmbeddable } from '../../services'; +import './styles.scss'; +import { VisualizeEmbeddable } from '../../../../visualizations/public'; + +interface Props { + embeddable: VisualizeEmbeddable; +} + +export function TimelinePanel(props: Props) { + const PanelComponent = getEmbeddable().getEmbeddablePanel(); + return ( + + + + + + + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/types.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/types.tsx new file mode 100644 index 000000000000..c70617e66651 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/types.tsx @@ -0,0 +1,14 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { VisLayer } from '../../types'; +import { VisualizeEmbeddable } from '../../../../visualizations/public'; + +export interface EventVisEmbeddableItem { + visLayer: VisLayer; + embeddable: VisualizeEmbeddable; +} + +export type EventVisEmbeddablesMap = Map; diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/utils.test.ts b/src/plugins/vis_augmenter/public/view_events_flyout/components/utils.test.ts new file mode 100644 index 000000000000..39ff9d53dd44 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/utils.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createMockErrorEmbeddable } from '../../mocks'; +import { getErrorMessage } from './utils'; + +describe('utils', () => { + describe('getErrorMessage', () => { + const errorMsg = 'oh no an error!'; + it('returns message when error field is string', async () => { + const errorEmbeddable = createMockErrorEmbeddable(); + errorEmbeddable.error = errorMsg; + expect(getErrorMessage(errorEmbeddable)).toEqual(errorMsg); + }); + it('returns message when error field is Error obj', async () => { + const errorEmbeddable = createMockErrorEmbeddable(); + errorEmbeddable.error = new Error(errorMsg); + expect(getErrorMessage(errorEmbeddable)).toEqual(errorMsg); + }); + }); +}); diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/utils.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/utils.tsx new file mode 100644 index 000000000000..4c06d3b87f0c --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/utils.tsx @@ -0,0 +1,243 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get } from 'lodash'; +import { EmbeddableStart, ErrorEmbeddable } from '../../../../embeddable/public'; +import { VisualizeEmbeddable, VisualizeInput } from '../../../../visualizations/public'; +import { getEmbeddable, getQueryService } from '../../services'; +import { + isPointInTimeEventsVisLayer, + PointInTimeEventsVisLayer, + VisFlyoutContext, + VisLayer, +} from '../../types'; +import { EventVisEmbeddableItem, EventVisEmbeddablesMap } from './types'; +import { QueryStart } from '../../../../data/public'; + +export function getErrorMessage(errorEmbeddable: ErrorEmbeddable): string { + return errorEmbeddable.error instanceof Error + ? errorEmbeddable.error.message + : errorEmbeddable.error; +} + +/** + * Given an embeddable, check if/where there is value (y) axes located on the left and/or + * right of the chart. This is needed so we can properly align all of the event + * charts in the flyout appropriately. + */ +function getValueAxisPositions(embeddable: VisualizeEmbeddable): { left: boolean; right: boolean } { + let hasLeftValueAxis = false; + let hasRightValueAxis = false; + if (embeddable !== undefined) { + const valueAxes = embeddable.vis.params.valueAxes; + const positions = valueAxes.map( + (valueAxis: { position: string }) => valueAxis.position + ) as string[]; + hasLeftValueAxis = positions.includes('left'); + hasRightValueAxis = positions.includes('right'); + } + return { + left: hasLeftValueAxis, + right: hasRightValueAxis, + }; +} + +/** + * Fetching the base vis to show in the flyout, based on the saved object ID. Add constraints + * such that it is static and won't auto-refresh within the flyout. + * @param savedObjectId the saved object id of the base vis + * @param embeddableStart Optional EmbeddableStart passed in for plugins to utilize the function + * @param queryServiceLoader Optional QueryStart passed in for plugins to utilize the function + */ +export async function fetchVisEmbeddable( + savedObjectId: string, + embeddableStart?: EmbeddableStart, + queryStart?: QueryStart +): Promise { + const embeddableLoader = embeddableStart ?? getEmbeddable(); + const embeddableVisFactory = embeddableLoader.getEmbeddableFactory('visualization'); + const queryService = queryStart ?? getQueryService(); + const contextInput = { + filters: queryService.filterManager.getFilters(), + query: queryService.queryString.getQuery(), + timeRange: queryService.timefilter.timefilter.getTime(), + }; + + const embeddable = (await embeddableVisFactory?.createFromSavedObject(savedObjectId, { + ...contextInput, + visAugmenterConfig: { + inFlyout: true, + flyoutContext: VisFlyoutContext.BASE_VIS, + }, + } as VisualizeInput)) as VisualizeEmbeddable | ErrorEmbeddable; + + if (embeddable instanceof ErrorEmbeddable) { + throw getErrorMessage(embeddable); + } + + embeddable.updateInput({ + // @ts-ignore + refreshConfig: { + value: 0, + pause: true, + }, + }); + + // By waiting for this to complete, embeddable.visLayers will be populated + await embeddable.populateVisLayers(); + + return embeddable; +} + +/** + * Fetching the base vis to show in the flyout, based on the saved object ID. Add constraints + * such that it is static and won't auto-refresh within the flyout. + * @param savedObjectId the saved object id of the base vis + * @param setTimeRange custom hook used in base component + * @param setVisEmbeddable custom hook used in base component + * @param setErrorMessage custom hook used in base component + */ +export async function fetchVisEmbeddableWithSetters( + savedObjectId: string, + setTimeRange: Function, + setVisEmbeddable: Function, + setErrorMessage: Function +): Promise { + try { + const embeddable = await fetchVisEmbeddable(savedObjectId); + setTimeRange(getQueryService().timefilter.timefilter.getTime()); + setVisEmbeddable(embeddable); + } catch (err: any) { + setErrorMessage(String(err)); + } +} + +/** + * For each VisLayer in the base vis embeddable, generate a new filtered vis + * embeddable (based off of the base vis), and pass in extra arguments to only + * show datapoints for that particular VisLayer. Partition them by + * plugin resource type via an EventVisEmbeddablesMap. + * @param savedObjectId the saved object id of the base vis embeddable + * @param embeddable the base vis embeddable + * @param setEventVisEmbeddablesMap custom hook used in base component + * @param setErrorMessage custom hook used in base component + */ +export async function createEventEmbeddables( + savedObjectId: string, + embeddable: VisualizeEmbeddable, + setEventVisEmbeddablesMap: Function, + setErrorMessage: Function +) { + const embeddableVisFactory = getEmbeddable().getEmbeddableFactory('visualization'); + try { + const { left, right } = getValueAxisPositions(embeddable); + const map = new Map() as EventVisEmbeddablesMap; + // Currently only support PointInTimeEventVisLayers. Different layer types + // may require different logic in here + const visLayers = (get(embeddable, 'visLayers', []) as VisLayer[]).filter((visLayer) => + isPointInTimeEventsVisLayer(visLayer) + ) as PointInTimeEventsVisLayer[]; + if (visLayers !== undefined) { + const contextInput = { + filters: embeddable.getInput().filters, + query: embeddable.getInput().query, + timeRange: embeddable.getInput().timeRange, + }; + + await Promise.all( + visLayers.map(async (visLayer) => { + const pluginResourceType = visLayer.pluginResource.type; + const eventEmbeddable = (await embeddableVisFactory?.createFromSavedObject( + savedObjectId, + { + ...contextInput, + visAugmenterConfig: { + visLayerResourceIds: [visLayer.pluginResource.id as string], + inFlyout: true, + flyoutContext: VisFlyoutContext.EVENT_VIS, + leftValueAxisPadding: left, + rightValueAxisPadding: right, + }, + } as VisualizeInput + )) as VisualizeEmbeddable | ErrorEmbeddable; + + if (eventEmbeddable instanceof ErrorEmbeddable) { + throw getErrorMessage(eventEmbeddable); + } + + eventEmbeddable.updateInput({ + // @ts-ignore + refreshConfig: { + value: 0, + pause: true, + }, + }); + + const curList = (map.get(pluginResourceType) === undefined + ? [] + : map.get(pluginResourceType)) as EventVisEmbeddableItem[]; + curList.push({ + visLayer, + embeddable: eventEmbeddable, + } as EventVisEmbeddableItem); + map.set(pluginResourceType, curList); + }) + ); + setEventVisEmbeddablesMap(map); + } + } catch (err: any) { + setErrorMessage(String(err)); + } +} + +/** + * Based on the base vis embeddable, generate a new filtered vis, and pass in extra + * arguments to only show the x-axis (timeline). + * @param savedObjectId the saved object id of the base vis + * @param embeddable the base vis embeddable + * @param setTimelineVisEmbeddable custom hook used in base component + * @param setErrorMessage custom hook used in base component + */ +export async function createTimelineEmbeddable( + savedObjectId: string, + embeddable: VisualizeEmbeddable, + setTimelineVisEmbeddable: Function, + setErrorMessage: Function +) { + const embeddableVisFactory = getEmbeddable().getEmbeddableFactory('visualization'); + try { + const { left, right } = getValueAxisPositions(embeddable); + const contextInput = { + filters: embeddable.getInput().filters, + query: embeddable.getInput().query, + timeRange: embeddable.getInput().timeRange, + }; + + const timelineEmbeddable = (await embeddableVisFactory?.createFromSavedObject(savedObjectId, { + ...contextInput, + visAugmenterConfig: { + inFlyout: true, + flyoutContext: VisFlyoutContext.TIMELINE_VIS, + leftValueAxisPadding: left, + rightValueAxisPadding: right, + }, + } as VisualizeInput)) as VisualizeEmbeddable | ErrorEmbeddable; + + if (timelineEmbeddable instanceof ErrorEmbeddable) { + throw getErrorMessage(timelineEmbeddable); + } + + timelineEmbeddable.updateInput({ + // @ts-ignore + refreshConfig: { + value: 0, + pause: true, + }, + }); + setTimelineVisEmbeddable(timelineEmbeddable); + } catch (err: any) { + setErrorMessage(String(err)); + } +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/components/view_events_flyout.tsx b/src/plugins/vis_augmenter/public/view_events_flyout/components/view_events_flyout.tsx new file mode 100644 index 000000000000..6205f4a7dd4b --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/components/view_events_flyout.tsx @@ -0,0 +1,155 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState, useEffect } from 'react'; +import { + EuiFlyoutBody, + EuiFlyoutHeader, + EuiFlyout, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiLoadingContent, +} from '@elastic/eui'; +import './styles.scss'; +import { VisualizeEmbeddable } from '../../../../visualizations/public'; +import { TimeRange } from '../../../../data/common'; +import { BaseVisItem } from './base_vis_item'; +import { DateRangeItem } from './date_range_item'; +import { LoadingFlyoutBody } from './loading_flyout_body'; +import { ErrorFlyoutBody } from './error_flyout_body'; +import { EventsPanel } from './events_panel'; +import { TimelinePanel } from './timeline_panel'; +import { + fetchVisEmbeddableWithSetters, + createEventEmbeddables, + createTimelineEmbeddable, +} from './utils'; +import { EventVisEmbeddablesMap } from './types'; + +interface Props { + onClose: () => void; + savedObjectId: string; +} + +export const DATE_RANGE_FORMAT = 'MM/DD/YYYY HH:mm'; + +export function ViewEventsFlyout(props: Props) { + const [visEmbeddable, setVisEmbeddable] = useState(undefined); + // This map persists a plugin resource type -> a list of vis embeddables + // for each VisLayer of that type + const [eventVisEmbeddablesMap, setEventVisEmbeddablesMap] = useState< + EventVisEmbeddablesMap | undefined + >(undefined); + const [timelineVisEmbeddable, setTimelineVisEmbeddable] = useState< + VisualizeEmbeddable | undefined + >(undefined); + const [timeRange, setTimeRange] = useState(undefined); + const [isLoading, setIsLoading] = useState(true); + const [errorMessage, setErrorMessage] = useState(undefined); + + function reload() { + visEmbeddable?.reload(); + eventVisEmbeddablesMap?.forEach((embeddableItems) => { + embeddableItems.forEach((embeddableItem) => { + embeddableItem.embeddable.reload(); + }); + }); + } + + useEffect(() => { + fetchVisEmbeddableWithSetters( + props.savedObjectId, + setTimeRange, + setVisEmbeddable, + setErrorMessage + ); + // adding all of the values to the deps array cause a circular re-render. we don't want + // to keep re-fetching the visEmbeddable after it is set. + /* eslint-disable react-hooks/exhaustive-deps */ + }, [props.savedObjectId]); + + useEffect(() => { + if (visEmbeddable?.visLayers) { + createEventEmbeddables( + props.savedObjectId, + visEmbeddable, + setEventVisEmbeddablesMap, + setErrorMessage + ); + createTimelineEmbeddable( + props.savedObjectId, + visEmbeddable, + setTimelineVisEmbeddable, + setErrorMessage + ); + } + }, [visEmbeddable?.visLayers]); + + useEffect(() => { + if ( + visEmbeddable !== undefined && + eventVisEmbeddablesMap !== undefined && + timeRange !== undefined && + timelineVisEmbeddable !== undefined + ) { + setIsLoading(false); + } + }, [visEmbeddable, eventVisEmbeddablesMap, timeRange, timelineVisEmbeddable]); + + return ( + <> + + + +

+ {isLoading ? ( + + ) : errorMessage ? ( + 'Error fetching events' + ) : ( + `${visEmbeddable?.getTitle()}` + )} +

+
+
+ {errorMessage ? ( + + ) : isLoading ? ( + + ) : ( + + + + + + + + + + + + + + + + + )} +
+ + ); +} diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/flyout_state.ts b/src/plugins/vis_augmenter/public/view_events_flyout/flyout_state.ts new file mode 100644 index 000000000000..4db90ed977e8 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/flyout_state.ts @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createGetterSetter } from '../../../opensearch_dashboards_utils/public'; + +export enum VIEW_EVENTS_FLYOUT_STATE { + OPEN = 'OPEN', + CLOSED = 'CLOSED', +} + +export const [getFlyoutState, setFlyoutState] = createGetterSetter< + keyof typeof VIEW_EVENTS_FLYOUT_STATE +>(VIEW_EVENTS_FLYOUT_STATE.CLOSED); + +// This is primarily used for mocking this module and each of its fns in tests. +// eslint-disable-next-line import/no-default-export +export default { VIEW_EVENTS_FLYOUT_STATE, getFlyoutState, setFlyoutState }; diff --git a/src/plugins/vis_augmenter/public/view_events_flyout/index.ts b/src/plugins/vis_augmenter/public/view_events_flyout/index.ts new file mode 100644 index 000000000000..3f1da0cedbb7 --- /dev/null +++ b/src/plugins/vis_augmenter/public/view_events_flyout/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './actions'; +export * from './components'; +export * from './flyout_state'; diff --git a/src/plugins/vis_augmenter/server/capabilities_provider.ts b/src/plugins/vis_augmenter/server/capabilities_provider.ts new file mode 100644 index 000000000000..db7bfc2b5393 --- /dev/null +++ b/src/plugins/vis_augmenter/server/capabilities_provider.ts @@ -0,0 +1,13 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const capabilitiesProvider = () => ({ + visAugmenter: { + show: false, + delete: true, + save: true, + saveQuery: true, + }, +}); diff --git a/src/plugins/vis_augmenter/server/index.ts b/src/plugins/vis_augmenter/server/index.ts new file mode 100644 index 000000000000..9fb8b7b695fa --- /dev/null +++ b/src/plugins/vis_augmenter/server/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PluginConfigDescriptor, PluginInitializerContext } from '../../../core/server'; +import { VisAugmenterPlugin } from './plugin'; +import { configSchema, VisAugmenterPluginConfigType } from '../config'; + +export const config: PluginConfigDescriptor = { + exposeToBrowser: { + pluginAugmentationEnabled: true, + }, + schema: configSchema, +}; +export function plugin(initializerContext: PluginInitializerContext) { + return new VisAugmenterPlugin(initializerContext); +} +export { VisAugmenterPluginSetup, VisAugmenterPluginStart } from './plugin'; diff --git a/src/plugins/vis_augmenter/server/plugin.ts b/src/plugins/vis_augmenter/server/plugin.ts new file mode 100644 index 000000000000..e482265ee290 --- /dev/null +++ b/src/plugins/vis_augmenter/server/plugin.ts @@ -0,0 +1,98 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { schema } from '@osd/config-schema'; +import { Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '../../../core/server'; +import { augmentVisSavedObjectType } from './saved_objects'; +import { capabilitiesProvider } from './capabilities_provider'; +import { VisAugmenterPluginConfigType } from '../config'; +import { + PLUGIN_AUGMENTATION_ENABLE_SETTING, + PLUGIN_AUGMENTATION_MAX_OBJECTS_SETTING, +} from '../common/constants'; +import { registerStatsRoute } from './routes/stats'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VisAugmenterPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VisAugmenterPluginStart {} + +export class VisAugmenterPlugin + implements Plugin { + private readonly logger: Logger; + private readonly config$: Observable; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + this.config$ = initializerContext.config.create(); + } + + public async setup(core: CoreSetup) { + this.logger.debug('VisAugmenter: Setup'); + core.savedObjects.registerType(augmentVisSavedObjectType); + core.capabilities.registerProvider(capabilitiesProvider); + + const config: VisAugmenterPluginConfigType = await this.config$.pipe(first()).toPromise(); + const isAugmentationEnabled = + config.pluginAugmentationEnabled === undefined ? true : config.pluginAugmentationEnabled; + + // Checks if the global yaml setting for enabling plugin augmentation is disabled. + // If it is disabled, remove the settings as we would not want to show these to the + // user due to it being disabled at the cluster level. + if (isAugmentationEnabled) { + core.uiSettings.register({ + [PLUGIN_AUGMENTATION_ENABLE_SETTING]: { + name: i18n.translate('visualization.enablePluginAugmentationTitle', { + defaultMessage: 'Enable plugin augmentation', + }), + value: true, + description: i18n.translate('visualization.enablePluginAugmentationText', { + defaultMessage: 'Plugin functionality can be accessed from line chart visualizations', + }), + category: ['visualization'], + schema: schema.boolean(), + }, + [PLUGIN_AUGMENTATION_MAX_OBJECTS_SETTING]: { + name: i18n.translate('visualization.enablePluginAugmentation.maxPluginObjectsTitle', { + defaultMessage: 'Max number of associated augmentations', + }), + value: 10, + description: i18n.translate( + 'visualization.enablePluginAugmentation.maxPluginObjectsText', + { + defaultMessage: + 'Associating more than 10 plugin resources per visualization can lead to performance ' + + 'issues and increase the cost of running clusters.', + } + ), + category: ['visualization'], + schema: schema.number({ min: 0 }), + }, + }); + } + + // Register server-side APIs + const router = core.http.createRouter(); + registerStatsRoute(router, this.logger); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('VisAugmenter: Started'); + return {}; + } + + public stop() {} +} diff --git a/src/plugins/vis_augmenter/server/routes/stats.ts b/src/plugins/vis_augmenter/server/routes/stats.ts new file mode 100644 index 000000000000..ffc038233bc8 --- /dev/null +++ b/src/plugins/vis_augmenter/server/routes/stats.ts @@ -0,0 +1,52 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Logger } from '@osd/logging'; +import { ResponseError } from '@opensearch-project/opensearch/lib/errors'; +import { + IOpenSearchDashboardsResponse, + IRouter, + SavedObjectsFindResponse, +} from '../../../../core/server'; +import { APP_API, APP_PATH, AugmentVisSavedObjectAttributes } from '../../common'; +import { PER_PAGE_VALUE } from '../../../saved_objects/common'; +import { getAugmentVisSavedObjects, getStats } from './stats_helpers'; + +export const registerStatsRoute = (router: IRouter, logger: Logger) => { + router.get( + { + path: `${APP_API}${APP_PATH.STATS}`, + validate: {}, + }, + async ( + context, + request, + response + ): Promise> => { + try { + const savedObjectsClient = context.core.savedObjects.client; + const augmentVisSavedObjects: SavedObjectsFindResponse = await getAugmentVisSavedObjects( + savedObjectsClient, + PER_PAGE_VALUE + ); + const stats = getStats(augmentVisSavedObjects); + return response.ok({ + body: stats, + }); + } catch (error: any) { + logger.error(error); + return response.customError({ + statusCode: error.statusCode || 500, + body: { + message: error.message, + attributes: { + error: error.body?.error || error.message, + }, + }, + }); + } + } + ); +}; diff --git a/src/plugins/vis_augmenter/server/routes/stats_helpers.test.ts b/src/plugins/vis_augmenter/server/routes/stats_helpers.test.ts new file mode 100644 index 000000000000..c0badd06e1ea --- /dev/null +++ b/src/plugins/vis_augmenter/server/routes/stats_helpers.test.ts @@ -0,0 +1,234 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsFindResult } from '../../../../../src/core/server'; +import { AugmentVisSavedObjectAttributes } from '../../common'; +import { getAugmentVisSavedObjects, getStats } from './stats_helpers'; + +const ORIGIN_PLUGIN_1 = 'origin-plugin-1'; +const ORIGIN_PLUGIN_2 = 'origin-plugin-2'; +const PLUGIN_RESOURCE_TYPE_1 = 'plugin-resource-type-1'; +const PLUGIN_RESOURCE_TYPE_2 = 'plugin-resource-type-2'; +const PLUGIN_RESOURCE_ID_1 = 'plugin-resource-id-1'; +const PLUGIN_RESOURCE_ID_2 = 'plugin-resource-id-2'; +const PLUGIN_RESOURCE_ID_3 = 'plugin-resource-id-3'; +const VIS_REF_NAME = 'visualization_0'; +const VIS_ID_1 = 'vis-id-1'; +const VIS_ID_2 = 'vis-id-2'; +const PER_PAGE = 4; + +const SINGLE_SAVED_OBJ = [ + { + attributes: { + originPlugin: ORIGIN_PLUGIN_1, + pluginResource: { + type: PLUGIN_RESOURCE_TYPE_1, + id: PLUGIN_RESOURCE_ID_1, + }, + visName: VIS_REF_NAME, + }, + references: [ + { + name: VIS_REF_NAME, + id: VIS_ID_1, + }, + ], + }, +] as Array>; + +const MULTIPLE_SAVED_OBJS = [ + { + attributes: { + originPlugin: ORIGIN_PLUGIN_1, + pluginResource: { + type: PLUGIN_RESOURCE_TYPE_1, + id: PLUGIN_RESOURCE_ID_1, + }, + visName: VIS_REF_NAME, + }, + references: [ + { + name: VIS_REF_NAME, + id: VIS_ID_1, + }, + ], + }, + { + attributes: { + originPlugin: ORIGIN_PLUGIN_2, + pluginResource: { + type: PLUGIN_RESOURCE_TYPE_2, + id: PLUGIN_RESOURCE_ID_2, + }, + visName: VIS_REF_NAME, + }, + references: [ + { + name: VIS_REF_NAME, + id: VIS_ID_1, + }, + ], + }, + { + attributes: { + originPlugin: ORIGIN_PLUGIN_2, + pluginResource: { + type: PLUGIN_RESOURCE_TYPE_2, + id: PLUGIN_RESOURCE_ID_2, + }, + visName: VIS_REF_NAME, + }, + references: [ + { + name: VIS_REF_NAME, + id: VIS_ID_2, + }, + ], + }, + { + attributes: { + originPlugin: ORIGIN_PLUGIN_2, + pluginResource: { + type: PLUGIN_RESOURCE_TYPE_2, + id: PLUGIN_RESOURCE_ID_3, + }, + visName: VIS_REF_NAME, + }, + references: [ + { + name: VIS_REF_NAME, + id: VIS_ID_1, + }, + ], + }, +] as Array>; + +describe('getAugmentVisSavedObjs()', function () { + const mockClient = { + find: jest.fn(), + }; + it('should return empty arr if no objs found', async function () { + mockClient.find.mockResolvedValueOnce({ + total: 0, + page: 1, + per_page: PER_PAGE, + saved_objects: [], + }); + + // @ts-ignore + const response = await getAugmentVisSavedObjects(mockClient, PER_PAGE); + expect(response.total).toEqual(0); + expect(response.saved_objects).toHaveLength(0); + }); + + it('should return all augment-vis saved objects', async function () { + mockClient.find.mockResolvedValueOnce({ + total: 4, + page: 1, + per_page: PER_PAGE, + saved_objects: MULTIPLE_SAVED_OBJS, + }); + + // @ts-ignore + const response = await getAugmentVisSavedObjects(mockClient, PER_PAGE); + expect(response.total).toEqual(4); + expect(response.saved_objects).toHaveLength(4); + expect(response.saved_objects[0].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_1); + expect(response.saved_objects[1].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_2); + expect(response.saved_objects[2].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_2); + expect(response.saved_objects[3].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_2); + }); + + it('should correctly perform pagination', async function () { + mockClient.find + .mockResolvedValueOnce({ + total: 5, + page: 1, + per_page: PER_PAGE, + saved_objects: MULTIPLE_SAVED_OBJS, + }) + .mockResolvedValueOnce({ + total: 5, + page: 2, + per_page: PER_PAGE, + saved_objects: SINGLE_SAVED_OBJ, + }); + + // @ts-ignore + const response = await getAugmentVisSavedObjects(mockClient, PER_PAGE); + expect(response.total).toEqual(5); + expect(response.saved_objects).toHaveLength(5); + expect(response.saved_objects[0].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_1); + expect(response.saved_objects[1].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_2); + expect(response.saved_objects[2].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_2); + expect(response.saved_objects[3].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_2); + expect(response.saved_objects[4].attributes.originPlugin).toEqual(ORIGIN_PLUGIN_1); + }); +}); + +describe('getStats()', function () { + it('should return total of 0 and empty mappings on empty response', function () { + const response = getStats({ + total: 0, + page: 1, + per_page: PER_PAGE, + saved_objects: [], + }); + expect(response.total_objs).toEqual(0); + expect(response.obj_breakdown.origin_plugin).toEqual({}); + expect(response.obj_breakdown.plugin_resource_type).toEqual({}); + expect(response.obj_breakdown.plugin_resource_id).toEqual({}); + expect(response.obj_breakdown.visualization_id).toEqual({}); + }); + + it('should return correct count and mappings on single-obj response', function () { + const response = getStats({ + total: 1, + page: 1, + per_page: PER_PAGE, + saved_objects: SINGLE_SAVED_OBJ, + }); + expect(response.total_objs).toEqual(1); + expect(response.obj_breakdown.origin_plugin).toEqual({ + [ORIGIN_PLUGIN_1]: 1, + }); + expect(response.obj_breakdown.plugin_resource_type).toEqual({ + [PLUGIN_RESOURCE_TYPE_1]: 1, + }); + expect(response.obj_breakdown.plugin_resource_id).toEqual({ + [PLUGIN_RESOURCE_ID_1]: 1, + }); + expect(response.obj_breakdown.visualization_id).toEqual({ + [VIS_ID_1]: 1, + }); + }); + + it('should return correct count and mappings on multiple-obj response', function () { + const response = getStats({ + total: MULTIPLE_SAVED_OBJS.length, + page: 1, + per_page: PER_PAGE, + saved_objects: MULTIPLE_SAVED_OBJS, + }); + expect(response.total_objs).toEqual(4); + expect(response.obj_breakdown.origin_plugin).toEqual({ + [ORIGIN_PLUGIN_1]: 1, + [ORIGIN_PLUGIN_2]: 3, + }); + expect(response.obj_breakdown.plugin_resource_type).toEqual({ + [PLUGIN_RESOURCE_TYPE_1]: 1, + [PLUGIN_RESOURCE_TYPE_2]: 3, + }); + expect(response.obj_breakdown.plugin_resource_id).toEqual({ + [PLUGIN_RESOURCE_ID_1]: 1, + [PLUGIN_RESOURCE_ID_2]: 2, + [PLUGIN_RESOURCE_ID_3]: 1, + }); + expect(response.obj_breakdown.visualization_id).toEqual({ + [VIS_ID_1]: 3, + [VIS_ID_2]: 1, + }); + }); +}); diff --git a/src/plugins/vis_augmenter/server/routes/stats_helpers.ts b/src/plugins/vis_augmenter/server/routes/stats_helpers.ts new file mode 100644 index 000000000000..174e68e529c9 --- /dev/null +++ b/src/plugins/vis_augmenter/server/routes/stats_helpers.ts @@ -0,0 +1,91 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get } from 'lodash'; +import { + SavedObjectsFindResponse, + SavedObjectsClientContract, +} from '../../../../../src/core/server'; +import { AugmentVisSavedObjectAttributes } from '../../common'; + +interface ObjectBreakdown { + origin_plugin: { [key: string]: number }; + plugin_resource_type: { [key: string]: number }; + plugin_resource_id: { [key: string]: number }; + visualization_id: { [key: string]: number }; +} + +interface VisAugmenterStats { + total_objs: number; + obj_breakdown: ObjectBreakdown; +} + +export const getAugmentVisSavedObjects = async ( + savedObjectsClient: SavedObjectsClientContract, + perPage: number +): Promise> => { + const augmentVisSavedObjects: SavedObjectsFindResponse = await savedObjectsClient?.find( + { + type: 'augment-vis', + perPage, + } + ); + // If there are more than perPage of objs, we need to make additional requests + if (augmentVisSavedObjects.total > perPage) { + const iterations = Math.ceil(augmentVisSavedObjects.total / perPage); + for (let i = 1; i < iterations; i++) { + const augmentVisSavedObjectsPage: SavedObjectsFindResponse = await savedObjectsClient?.find( + { + type: 'augment-vis', + perPage, + page: i + 1, + } + ); + augmentVisSavedObjects.saved_objects = [ + ...augmentVisSavedObjects.saved_objects, + ...augmentVisSavedObjectsPage.saved_objects, + ]; + } + } + return augmentVisSavedObjects; +}; + +/** + * Given the _find response that contains all of the saved objects, iterate through them and + * increment counters for each unique value we are tracking + */ +export const getStats = ( + resp: SavedObjectsFindResponse +): VisAugmenterStats => { + const originPluginMap = {} as { [originPlugin: string]: number }; + const pluginResourceTypeMap = {} as { [pluginResourceType: string]: number }; + const pluginResourceIdMap = {} as { [pluginResourceId: string]: number }; + const visualizationIdMap = {} as { [visualizationId: string]: number }; + + resp.saved_objects.forEach((augmentVisObj) => { + const originPlugin = augmentVisObj.attributes.originPlugin; + const pluginResourceType = augmentVisObj.attributes.pluginResource.type; + const pluginResourceId = augmentVisObj.attributes.pluginResource.id; + const visualizationId = augmentVisObj.references[0].id as string; + + originPluginMap[originPlugin] = (get(originPluginMap, originPlugin, 0) as number) + 1; + pluginResourceTypeMap[pluginResourceType] = + (get(pluginResourceTypeMap, pluginResourceType, 0) as number) + 1; + pluginResourceIdMap[pluginResourceId] = + (get(pluginResourceIdMap, pluginResourceId, 0) as number) + 1; + visualizationIdMap[visualizationId] = + (get(visualizationIdMap, visualizationId, 0) as number) + 1; + }); + + return { + total_objs: resp.total, + obj_breakdown: { + origin_plugin: originPluginMap, + plugin_resource_type: pluginResourceTypeMap, + plugin_resource_id: pluginResourceIdMap, + visualization_id: visualizationIdMap, + }, + }; +}; diff --git a/src/plugins/vis_augmenter/server/saved_objects/augment_vis.ts b/src/plugins/vis_augmenter/server/saved_objects/augment_vis.ts new file mode 100644 index 000000000000..52188d52998a --- /dev/null +++ b/src/plugins/vis_augmenter/server/saved_objects/augment_vis.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsType } from 'opensearch-dashboards/server'; + +export const augmentVisSavedObjectType: SavedObjectsType = { + name: 'augment-vis', + hidden: false, + namespaceType: 'single', + management: { + importableAndExportable: true, + getTitle(obj) { + return `augment-vis-${obj?.attributes?.originPlugin}`; + }, + getEditUrl(obj) { + return `/management/opensearch-dashboards/objects/savedAugmentVis/${encodeURIComponent( + obj.id + )}`; + }, + }, + mappings: { + properties: { + title: { type: 'text' }, + description: { type: 'text' }, + originPlugin: { type: 'text' }, + pluginResource: { + properties: { + type: { type: 'text' }, + id: { type: 'text' }, + }, + }, + visName: { type: 'keyword', index: false, doc_values: false }, + visLayerExpressionFn: { + properties: { + type: { type: 'text' }, + name: { type: 'text' }, + // keeping generic to not limit what users may pass as args to their fns + // users may not have this field at all, if no args are needed + args: { type: 'object', dynamic: true }, + }, + }, + version: { type: 'integer' }, + }, + }, +}; diff --git a/src/plugins/vis_augmenter/server/saved_objects/index.ts b/src/plugins/vis_augmenter/server/saved_objects/index.ts new file mode 100644 index 000000000000..b96dbd4b2a58 --- /dev/null +++ b/src/plugins/vis_augmenter/server/saved_objects/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { augmentVisSavedObjectType } from './augment_vis'; diff --git a/src/plugins/vis_builder/public/assets/vis_builder_icon.svg b/src/plugins/vis_builder/public/assets/vis_builder_icon.svg deleted file mode 100644 index 69da8016eb12..000000000000 --- a/src/plugins/vis_builder/public/assets/vis_builder_icon.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/plugins/vis_builder/public/assets/vis_builder_icon_secondary_fill.svg b/src/plugins/vis_builder/public/assets/vis_builder_icon_secondary_fill.svg deleted file mode 100644 index cdaad42f6276..000000000000 --- a/src/plugins/vis_builder/public/assets/vis_builder_icon_secondary_fill.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 90048ba91322..3c0bf0337369 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 @@ -26,7 +26,6 @@ import { VisBuilderOutput, VISBUILDER_EMBEDDABLE, } from './vis_builder_embeddable'; -import visBuilderIcon from '../assets/vis_builder_icon.svg'; import { getStateFromSavedObject } from '../saved_visualizations/transforms'; import { getHttp, @@ -55,7 +54,7 @@ export class VisBuilderEmbeddableFactory name: PLUGIN_NAME, includeFields: ['visualizationState'], type: VISBUILDER_SAVED_OBJECT, - getIconForSavedObject: () => visBuilderIcon, + getIconForSavedObject: () => 'visBuilder', }; // TODO: Would it be better to explicitly declare start service dependencies? diff --git a/src/plugins/vis_builder/public/plugin.ts b/src/plugins/vis_builder/public/plugin.ts index 1445de923010..4e8f020d1fe8 100644 --- a/src/plugins/vis_builder/public/plugin.ts +++ b/src/plugins/vis_builder/public/plugin.ts @@ -24,8 +24,6 @@ import { VisBuilderStart, } from './types'; import { VisBuilderEmbeddableFactory, VISBUILDER_EMBEDDABLE } from './embeddable'; -import visBuilderIconSecondaryFill from './assets/vis_builder_icon_secondary_fill.svg'; -import visBuilderIcon from './assets/vis_builder_icon.svg'; import { EDIT_PATH, PLUGIN_ID, @@ -189,7 +187,7 @@ export class VisBuilderPlugin description: i18n.translate('visBuilder.visPicker.description', { defaultMessage: 'Create visualizations using the new VisBuilder', }), - icon: visBuilderIconSecondaryFill, + icon: 'visBuilder', stage: 'experimental', aliasApp: PLUGIN_ID, aliasPath: '#/', @@ -200,7 +198,7 @@ export class VisBuilderPlugin description: attributes?.description, editApp: PLUGIN_ID, editUrl: `${EDIT_PATH}/${encodeURIComponent(id)}`, - icon: visBuilderIcon, + icon: 'visBuilder', id, savedObjectType: VISBUILDER_SAVED_OBJECT, stage: 'experimental', diff --git a/src/plugins/vis_default_editor/public/components/controls/raw_json.tsx b/src/plugins/vis_default_editor/public/components/controls/raw_json.tsx index cdef0c2c2042..38a645e62e51 100644 --- a/src/plugins/vis_default_editor/public/components/controls/raw_json.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/raw_json.tsx @@ -100,7 +100,7 @@ function RawJsonParamEditor({ <> - + @@ -83,7 +83,7 @@ function MarkdownOptions({ stateParams, setValue }: VisOptionsProps onMarkdownUpdate(value)} fullWidth={true} diff --git a/src/plugins/vis_type_markdown/public/markdown_vis.scss b/src/plugins/vis_type_markdown/public/markdown_vis.scss index 97cfc4b151c7..1a72f2dc8576 100644 --- a/src/plugins/vis_type_markdown/public/markdown_vis.scss +++ b/src/plugins/vis_type_markdown/public/markdown_vis.scss @@ -5,18 +5,8 @@ // mkdChart__legend--small // mkdChart__legend-isLoading -.mkdVis { - padding: $euiSizeS; - width: 100%; -} - .visEditor--markdown { - .visEditorSidebar__config > *, - .visEditor--markdown__textarea { + .visEditorSidebar__config > * { flex-grow: 1; } - - .mkdEditor { - height: 100%; - } } diff --git a/src/plugins/vis_type_markdown/public/markdown_vis_controller.tsx b/src/plugins/vis_type_markdown/public/markdown_vis_controller.tsx index befa2dce8fcd..4d2ff853dd70 100644 --- a/src/plugins/vis_type_markdown/public/markdown_vis_controller.tsx +++ b/src/plugins/vis_type_markdown/public/markdown_vis_controller.tsx @@ -29,6 +29,7 @@ */ import React, { useEffect } from 'react'; +import { EuiPanel } from '@elastic/eui'; import { Markdown } from '../../opensearch_dashboards_react/public'; import { MarkdownVisParams } from './types'; @@ -47,13 +48,18 @@ const MarkdownVisComponent = ({ useEffect(renderComplete); // renderComplete will be called after each render to signal, that we are done with rendering. return ( -
+ -
+ ); }; diff --git a/src/plugins/vis_type_table/public/components/table_vis_app.scss b/src/plugins/vis_type_table/public/components/table_vis_app.scss index f0b82a1cd8d8..f6a5538a3ccf 100644 --- a/src/plugins/vis_type_table/public/components/table_vis_app.scss +++ b/src/plugins/vis_type_table/public/components/table_vis_app.scss @@ -1,7 +1,5 @@ // Container for the Table Visualization component .visTable { - display: flex; - flex-direction: column; flex: 1 0 0; overflow: auto; @@ -10,15 +8,5 @@ // Group container for table visualization components .visTable__group { - padding: $euiSizeS; - margin-bottom: $euiSizeL; - display: flex; - flex-direction: column; flex: 0 0 auto; } - -// Modifier for visTables__group when displayed in columns -.visTable__groupInColumns { - flex-direction: row; - align-items: flex-start; -} diff --git a/src/plugins/vis_type_table/public/components/table_vis_app.test.tsx b/src/plugins/vis_type_table/public/components/table_vis_app.test.tsx index 37cb753765f8..f2a347dcd0a2 100644 --- a/src/plugins/vis_type_table/public/components/table_vis_app.test.tsx +++ b/src/plugins/vis_type_table/public/components/table_vis_app.test.tsx @@ -75,7 +75,7 @@ describe('TableVisApp', () => { handlers={handlersMock} /> ); - expect(container.outerHTML.includes('visTable visTable__groupInColumns')).toBe(true); + expect(container.outerHTML.includes('visTable')).toBe(true); expect(getByTestId('TableVisComponentGroup')).toBeInTheDocument(); }); diff --git a/src/plugins/vis_type_table/public/components/table_vis_app.tsx b/src/plugins/vis_type_table/public/components/table_vis_app.tsx index 81f4d775f1e5..cbde913452d1 100644 --- a/src/plugins/vis_type_table/public/components/table_vis_app.tsx +++ b/src/plugins/vis_type_table/public/components/table_vis_app.tsx @@ -5,10 +5,10 @@ import './table_vis_app.scss'; import React, { useEffect } from 'react'; -import classNames from 'classnames'; import { CoreStart } from 'opensearch-dashboards/public'; import { I18nProvider } from '@osd/i18n/react'; import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import { EuiFlexGroup } from '@elastic/eui'; import { PersistedState } from '../../../visualizations/public'; import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; import { TableVisData } from '../table_vis_response_handler'; @@ -35,17 +35,17 @@ export const TableVisApp = ({ handlers.done(); }, [handlers]); - const className = classNames('visTable', { - // eslint-disable-next-line @typescript-eslint/naming-convention - visTable__groupInColumns: direction === 'column', - }); - const tableUiState: TableUiState = getTableUIState(handlers.uiState as PersistedState); return ( -
+ {table ? ( )} -
+
); diff --git a/src/plugins/vis_type_table/public/components/table_vis_component.tsx b/src/plugins/vis_type_table/public/components/table_vis_component.tsx index 79cf768f66e8..c0e4ab61ae8b 100644 --- a/src/plugins/vis_type_table/public/components/table_vis_component.tsx +++ b/src/plugins/vis_type_table/public/components/table_vis_component.tsx @@ -5,7 +5,13 @@ import React, { useCallback, useMemo } from 'react'; import { orderBy } from 'lodash'; -import { EuiDataGridProps, EuiDataGrid, EuiDataGridSorting, EuiTitle } from '@elastic/eui'; +import { + EuiDataGridProps, + EuiDataGrid, + EuiDataGridSorting, + EuiTitle, + EuiFlexItem, +} from '@elastic/eui'; import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; import { FormattedTableContext } from '../table_vis_response_handler'; @@ -102,7 +108,7 @@ export const TableVisComponent = ({ : undefined; return ( - <> + {title && (

{title}

@@ -140,6 +146,6 @@ export const TableVisComponent = ({ ), }} /> - +
); }; diff --git a/src/plugins/vis_type_table/public/components/table_vis_component_group.tsx b/src/plugins/vis_type_table/public/components/table_vis_component_group.tsx index af8fd8048cbc..64c7ce91f4b7 100644 --- a/src/plugins/vis_type_table/public/components/table_vis_component_group.tsx +++ b/src/plugins/vis_type_table/public/components/table_vis_component_group.tsx @@ -4,8 +4,8 @@ */ import React, { memo } from 'react'; - import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import { EuiFlexItem } from '@elastic/eui'; import { TableGroup } from '../table_vis_response_handler'; import { TableVisConfig } from '../types'; import { TableVisComponent } from './table_vis_component'; @@ -23,7 +23,7 @@ export const TableVisComponentGroup = memo( return ( <> {tableGroups.map(({ table, title }) => ( -
+ -
+
))} ); diff --git a/src/plugins/vis_type_tagcloud/public/components/__snapshots__/tag_cloud_visualization.test.js.snap b/src/plugins/vis_type_tagcloud/public/components/__snapshots__/tag_cloud_visualization.test.js.snap index d7707f64d8a4..4f4e2eeab4be 100644 --- a/src/plugins/vis_type_tagcloud/public/components/__snapshots__/tag_cloud_visualization.test.js.snap +++ b/src/plugins/vis_type_tagcloud/public/components/__snapshots__/tag_cloud_visualization.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TagCloudVisualizationTest TagCloudVisualization - basics simple draw 1`] = `"CNINUSDEBR"`; +exports[`TagCloudVisualizationTest TagCloudVisualization - basics simple draw 1`] = `"CNINUSDEBR"`; -exports[`TagCloudVisualizationTest TagCloudVisualization - basics with param change 1`] = `"CNINUSDEBR"`; +exports[`TagCloudVisualizationTest TagCloudVisualization - basics with param change 1`] = `"CNINUSDEBR"`; -exports[`TagCloudVisualizationTest TagCloudVisualization - basics with resize 1`] = `"CNINUSDEBR"`; +exports[`TagCloudVisualizationTest TagCloudVisualization - basics with resize 1`] = `"CNINUSDEBR"`; diff --git a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.test.js b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.test.js index a75644667e73..56f528356e83 100644 --- a/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.test.js +++ b/src/plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.test.js @@ -34,8 +34,9 @@ import { TagCloudVisualization } from './tag_cloud_visualization'; import { setFormatService } from '../services'; import { dataPluginMock } from '../../../data/public/mocks'; import { setHTMLElementOffset, setSVGElementGetBBox } from '../../../../test_utils/public'; +import { euiPaletteColorBlind } from '@elastic/eui'; -const seedColors = ['#00a69b', '#57c17b', '#6f87d8', '#663db8', '#bc52bc', '#9e3533', '#daa05d']; +const seedColors = euiPaletteColorBlind(); describe('TagCloudVisualizationTest', () => { let domNode; diff --git a/src/plugins/vis_type_timeline/public/helpers/panel_utils.ts b/src/plugins/vis_type_timeline/public/helpers/panel_utils.ts index 35089811c08b..a7bcf0f7786e 100644 --- a/src/plugins/vis_type_timeline/public/helpers/panel_utils.ts +++ b/src/plugins/vis_type_timeline/public/helpers/panel_utils.ts @@ -32,6 +32,7 @@ import { cloneDeep, defaults, mergeWith, compact } from 'lodash'; import $ from 'jquery'; import moment, { Moment } from 'moment-timezone'; +import { euiPaletteColorBlind } from '@elastic/eui'; import { TimefilterContract } from 'src/plugins/data/public'; import { IUiSettingsClient } from 'opensearch-dashboards/public'; @@ -65,18 +66,7 @@ interface TimeRangeBounds { export const ACTIVE_CURSOR = 'ACTIVE_CURSOR_TIMELINE'; export const eventBus = $({}); -const colors = [ - '#01A4A4', - '#C66', - '#D0D102', - '#616161', - '#00A1CB', - '#32742C', - '#F18D05', - '#113F8C', - '#61AE24', - '#D70060', -]; +const colors = euiPaletteColorBlind(); const SERIES_ID_ATTR = 'data-series-id'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/markdown_editor.js b/src/plugins/vis_type_timeseries/public/application/components/markdown_editor.js index f793e1ff724a..82814d4fbec9 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/markdown_editor.js +++ b/src/plugins/vis_type_timeseries/public/application/components/markdown_editor.js @@ -126,7 +126,7 @@ export class MarkdownEditor extends Component {
`; +exports[`VegaVisualizations VegaVisualization - basics should show vega graph (may fail in dev env) 1`] = `
  • Cannot read properties of undefined (reading 'get')
`; + +exports[`VegaVisualizations VegaVisualization - basics should show vegalite graph and update on resize (may fail in dev env) 1`] = `
  • Cannot read properties of undefined (reading 'get')
`; + +exports[`VegaVisualizations VegaVisualization - basics should show vegalite graph and update on resize (may fail in dev env) 2`] = `
  • Cannot read properties of undefined (reading 'get')
`; + exports[`VegaVisualizations VegaVisualization - basics should show vega graph (may fail in dev env) 1`] = `
`; exports[`VegaVisualizations VegaVisualization - basics should show vegalite graph and update on resize (may fail in dev env) 1`] = `
  • "width" and "height" params are ignored because "autosize" is enabled. Set "autosize": "none" to disable
`; diff --git a/src/plugins/vis_type_vega/public/components/vega_vis_editor.tsx b/src/plugins/vis_type_vega/public/components/vega_vis_editor.tsx index 86343ae10b0d..5fe1cbcfa6cd 100644 --- a/src/plugins/vis_type_vega/public/components/vega_vis_editor.tsx +++ b/src/plugins/vis_type_vega/public/components/vega_vis_editor.tsx @@ -37,7 +37,7 @@ import { i18n } from '@osd/i18n'; import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; import { getNotifications } from '../services'; -import { VisParams } from '../vega_fn'; +import { VisParams } from '../expressions/vega_fn'; import { VegaHelpMenu } from './vega_help_menu'; import { VegaActionsMenu } from './vega_actions_menu'; diff --git a/src/plugins/vis_type_vega/public/data_model/types.ts b/src/plugins/vis_type_vega/public/data_model/types.ts index cd6cbc94bcc7..35198f846f02 100644 --- a/src/plugins/vis_type_vega/public/data_model/types.ts +++ b/src/plugins/vis_type_vega/public/data_model/types.ts @@ -32,6 +32,8 @@ import { SearchResponse, SearchParams } from 'elasticsearch'; import { Filter } from 'src/plugins/data/public'; import { DslQuery } from 'src/plugins/data/common'; +import { Signal } from 'vega'; +import { VisAugmenterEmbeddableConfig, VisLayerTypes } from 'src/plugins/vis_augmenter/public'; import { OpenSearchQueryParser } from './opensearch_query_parser'; import { EmsFileParser } from './ems_file_parser'; import { UrlParser } from './url_parser'; @@ -113,6 +115,9 @@ export interface OpenSearchDashboards { hideWarnings: boolean; type: string; renderer: Renderer; + visibleVisLayers?: Map; + signals?: { [markId: string]: Signal[] }; + visAugmenterConfig?: VisAugmenterEmbeddableConfig; } export interface VegaSpec { diff --git a/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js b/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js index 8ceb565fa8c0..421b99790dc1 100644 --- a/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js +++ b/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js @@ -33,6 +33,7 @@ import { euiThemeVars } from '@osd/ui-shared-deps/theme'; import { euiPaletteColorBlind } from '@elastic/eui'; import { VegaParser } from './vega_parser'; import { bypassExternalUrlCheck } from '../vega_view/vega_base_view'; +import { VisLayerTypes } from '../../../vis_augmenter/public'; jest.mock('../services'); @@ -388,6 +389,25 @@ describe('VegaParser._parseConfig', () => { check({ config: { kibana: { a: 1 } } }, { a: 1 }, { config: {} }) ); test('_hostConfig', check({ _hostConfig: { a: 1 } }, { a: 1 }, {}, 1)); + test( + 'visibleVisLayers conversion to map', + check( + { + config: { + kibana: { + hideWarnings: true, + visibleVisLayers: [[VisLayerTypes.PointInTimeEvents, true]], + }, + }, + }, + { + hideWarnings: true, + visibleVisLayers: new Map([[VisLayerTypes.PointInTimeEvents, true]]), + }, + { config: {} }, + 0 + ) + ); }); describe('VegaParser._compileWithAutosize', () => { diff --git a/src/plugins/vis_type_vega/public/data_model/vega_parser.ts b/src/plugins/vis_type_vega/public/data_model/vega_parser.ts index 64ed96f7e3e7..4bdd724dbead 100644 --- a/src/plugins/vis_type_vega/public/data_model/vega_parser.ts +++ b/src/plugins/vis_type_vega/public/data_model/vega_parser.ts @@ -36,6 +36,7 @@ import { euiPaletteColorBlind } from '@elastic/eui'; import { euiThemeVars } from '@osd/ui-shared-deps/theme'; import { i18n } from '@osd/i18n'; // @ts-ignore +import { Signal } from 'vega'; import { vega, vegaLite } from '../lib/vega'; import { OpenSearchQueryParser } from './opensearch_query_parser'; import { Utils } from './utils'; @@ -44,6 +45,7 @@ import { UrlParser } from './url_parser'; import { SearchAPI } from './search_api'; import { TimeCache } from './time_cache'; import { IServiceSettings } from '../../../maps_legacy/public'; +import { VisAugmenterEmbeddableConfig, VisLayerTypes } from '../../../vis_augmenter/public'; import { Bool, Data, @@ -92,6 +94,8 @@ export class VegaParser { getServiceSettings: () => Promise; filters: Bool; timeCache: TimeCache; + visibleVisLayers: Map; + visAugmenterConfig: VisAugmenterEmbeddableConfig; constructor( spec: VegaSpec | string, @@ -102,6 +106,8 @@ export class VegaParser { ) { this.spec = spec as VegaSpec; this.hideWarnings = false; + this.visibleVisLayers = new Map(); + this.visAugmenterConfig = {} as VisAugmenterEmbeddableConfig; this.error = undefined; this.warnings = []; @@ -158,6 +164,8 @@ The URL is an identifier only. OpenSearch Dashboards and your browser will never this._config = this._parseConfig(); this.hideWarnings = !!this._config.hideWarnings; + this.visibleVisLayers = this._config.visibleVisLayers; + this.visAugmenterConfig = this._config.visAugmenterConfig; this.useMap = this._config.type === 'map'; this.renderer = this._config.renderer === 'svg' ? 'svg' : 'canvas'; this.tooltips = this._parseTooltips(); @@ -190,6 +198,13 @@ The URL is an identifier only. OpenSearch Dashboards and your browser will never contains: 'padding', }; + // If we are showing PointInTimeEventsVisLayers, it means we are showing a base vis + event vis. + // Because this will be using a vconcat spec, we cannot use the default autosize settings, or set + // top-level height/width values. + // See limitations: https://vega.github.io/vega-lite/docs/size.html#limitations + const showPointInTimeEvents = + this.visibleVisLayers?.get(VisLayerTypes.PointInTimeEvents) === true; + let autosize = this.spec.autosize; let useResize = true; @@ -220,6 +235,8 @@ The URL is an identifier only. OpenSearch Dashboards and your browser will never contains: string; }; useResize = Boolean(autosize?.type && autosize?.type !== 'none'); + } else if (showPointInTimeEvents) { + autosize = undefined; } else { autosize = defaultAutosize; } @@ -243,7 +260,7 @@ The URL is an identifier only. OpenSearch Dashboards and your browser will never ); } - if (useResize) { + if (useResize && !showPointInTimeEvents) { this.spec.width = 'container'; this.spec.height = 'container'; } @@ -304,6 +321,52 @@ The URL is an identifier only. OpenSearch Dashboards and your browser will never delete this.spec.autosize; } } + + if (this._config?.signals) { + Object.entries(this._config?.signals).forEach(([markId, signals]: [string, any]) => { + const mark = this.getMarkWithStyle(this.spec.marks, markId); + + if (mark) { + signals.forEach((signal: Signal) => { + signal.on?.forEach((eventObj) => { + // We are prepending mark name here so that the signals only listens to the events on + // the elements related to this mark + eventObj.events = `@${mark.name}:${eventObj.events}`; + }); + }); + this.spec.signals = (this.spec.signals || []).concat(signals); + } + }); + } + } + + /** + * This method recursively looks for a mark that includes the given style. + * Returns undefined if it doesn't find it. + */ + getMarkWithStyle(marks: any[], style: string): any { + if (!marks) { + return undefined; + } + + if (Array.isArray(marks)) { + const markWithStyle = marks.find((mark) => { + return mark.style?.includes(style); + }); + + if (markWithStyle) { + return markWithStyle; + } + + for (let i = 0; i < marks.length; i++) { + const res = this.getMarkWithStyle(marks[i].marks, style); + if (res) { + return res; + } + } + + return undefined; + } } /** @@ -386,6 +449,10 @@ The URL is an identifier only. OpenSearch Dashboards and your browser will never ) ); } + // Converting the visibleVisLayers array back to a map + if (result.visibleVisLayers !== undefined && Array.isArray(result.visibleVisLayers)) { + result.visibleVisLayers = new Map(result.visibleVisLayers); + } } } return result || {}; diff --git a/src/plugins/vis_type_vega/public/expressions/__mocks__/helpers.ts b/src/plugins/vis_type_vega/public/expressions/__mocks__/helpers.ts new file mode 100644 index 000000000000..0dd50913d5f9 --- /dev/null +++ b/src/plugins/vis_type_vega/public/expressions/__mocks__/helpers.ts @@ -0,0 +1,21 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const complexDatatable = + '{"type":"opensearch_dashboards_datatable","rows":[{"col-0-2":1672214400000,"col-1-1":44,"col-2-3":60.9375},{"col-0-2":1672300800000,"col-1-1":150,"col-2-3":82.5},{"col-0-2":1672387200000,"col-1-1":154,"col-2-3":79.5},{"col-0-2":1672473600000,"col-1-1":144,"col-2-3":75.875},{"col-0-2":1672560000000,"col-1-1":133,"col-2-3":259.25},{"col-0-2":1672646400000,"col-1-1":149,"col-2-3":90},{"col-0-2":1672732800000,"col-1-1":152,"col-2-3":79.0625},{"col-0-2":1672819200000,"col-1-1":144,"col-2-3":82.5},{"col-0-2":1672905600000,"col-1-1":166,"col-2-3":85.25},{"col-0-2":1672992000000,"col-1-1":151,"col-2-3":92},{"col-0-2":1673078400000,"col-1-1":143,"col-2-3":90.75},{"col-0-2":1673164800000,"col-1-1":148,"col-2-3":92},{"col-0-2":1673251200000,"col-1-1":146,"col-2-3":83.25},{"col-0-2":1673337600000,"col-1-1":137,"col-2-3":98},{"col-0-2":1673424000000,"col-1-1":152,"col-2-3":83.6875},{"col-0-2":1673510400000,"col-1-1":152,"col-2-3":83.6875},{"col-0-2":1673596800000,"col-1-1":151,"col-2-3":87.4375},{"col-0-2":1673683200000,"col-1-1":157,"col-2-3":63.75},{"col-0-2":1673769600000,"col-1-1":151,"col-2-3":81.5625},{"col-0-2":1673856000000,"col-1-1":152,"col-2-3":100.6875},{"col-0-2":1673942400000,"col-1-1":142,"col-2-3":98},{"col-0-2":1674028800000,"col-1-1":151,"col-2-3":100.8125},{"col-0-2":1674115200000,"col-1-1":163,"col-2-3":83.6875},{"col-0-2":1674201600000,"col-1-1":156,"col-2-3":85.8125},{"col-0-2":1674288000000,"col-1-1":153,"col-2-3":98},{"col-0-2":1674374400000,"col-1-1":162,"col-2-3":75.9375},{"col-0-2":1674460800000,"col-1-1":152,"col-2-3":113.375},{"col-0-2":1674547200000,"col-1-1":159,"col-2-3":73.625},{"col-0-2":1674633600000,"col-1-1":165,"col-2-3":72.8125},{"col-0-2":1674720000000,"col-1-1":153,"col-2-3":113.375},{"col-0-2":1674806400000,"col-1-1":149,"col-2-3":82.5},{"col-0-2":1674892800000,"col-1-1":94,"col-2-3":54}],"columns":[{"id":"col-0-2","name":"order_date per day","meta":{"type":"date_histogram","indexPatternId":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","aggConfigParams":{"field":"order_date","timeRange":{"from":"now-90d","to":"now"},"useNormalizedOpenSearchInterval":true,"scaleMetricValues":false,"interval":"auto","drop_partials":false,"min_doc_count":1,"extended_bounds":{}}}},{"id":"col-1-1","name":"Count","meta":{"type":"count","indexPatternId":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","aggConfigParams":{}}},{"id":"col-2-3","name":"Max products.min_price","meta":{"type":"max","indexPatternId":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","aggConfigParams":{"field":"products.min_price"}}}]}'; +export const complexVisParams = + '{"addLegend":true,"addTimeMarker":true,"addTooltip":true,"categoryAxes":[{"id":"CategoryAxis-1","labels":{"filter":true,"show":true,"truncate":100},"position":"bottom","scale":{"type":"linear"},"show":true,"style":{},"title":{},"type":"category"}],"grid":{"categoryLines":false,"valueAxis":"ValueAxis-1"},"labels":{},"legendPosition":"bottom","seriesParams":[{"data":{"id":"1","label":"Count"},"drawLinesBetweenPoints":true,"interpolate":"linear","lineWidth":2,"mode":"normal","show":true,"showCircles":true,"type":"line","valueAxis":"ValueAxis-1"},{"data":{"id":"3","label":"Max products.min_price"},"drawLinesBetweenPoints":true,"interpolate":"linear","lineWidth":2,"mode":"normal","show":true,"showCircles":true,"type":"line","valueAxis":"ValueAxis-1"}],"thresholdLine":{"color":"#E7664C","show":true,"style":"dashed","value":100,"width":1},"times":[],"type":"line","valueAxes":[{"id":"ValueAxis-1","labels":{"filter":false,"rotate":75,"show":true,"truncate":100},"name":"RightAxis-1","position":"right","scale":{"mode":"normal","type":"linear"},"show":true,"style":{},"title":{"text":"Count"},"type":"value"}]}'; +export const complexDimensions = + '{"x":{"accessor":0,"format":{"id":"date","params":{"pattern":"YYYY-MM-DD"}},"params":{"date":true,"interval":"P1D","intervalESValue":1,"intervalESUnit":"d","format":"YYYY-MM-DD","bounds":{"min":"2022-11-19T03:26:04.730Z","max":"2023-02-17T03:26:04.730Z"}},"label":"order_date per day","aggType":"date_histogram"},"y":[{"accessor":1,"format":{"id":"number"},"params":{},"label":"Count","aggType":"count"},{"accessor":2,"format":{"id":"number","params":{"parsedUrl":{"origin":"http://localhost:5603","pathname":"/rao/app/visualize","basePath":"/rao"}}},"params":{},"label":"Max products.min_price","aggType":"max"}]}'; + +export const noXAxisDimensions = + '{"x":null,"y":[{"accessor":0,"format":{"id":"number"},"params":{},"label":"Count","aggType":"count"}]}'; + +export const simpleDatatable = + '{"type":"opensearch_dashboards_datatable","rows":[{"col-0-2":1672214400000,"col-1-1":44},{"col-0-2":1672300800000,"col-1-1":150},{"col-0-2":1672387200000,"col-1-1":154},{"col-0-2":1672473600000,"col-1-1":144},{"col-0-2":1672560000000,"col-1-1":133},{"col-0-2":1672646400000,"col-1-1":149},{"col-0-2":1672732800000,"col-1-1":152},{"col-0-2":1672819200000,"col-1-1":144},{"col-0-2":1672905600000,"col-1-1":166},{"col-0-2":1672992000000,"col-1-1":151},{"col-0-2":1673078400000,"col-1-1":143},{"col-0-2":1673164800000,"col-1-1":148},{"col-0-2":1673251200000,"col-1-1":146},{"col-0-2":1673337600000,"col-1-1":137},{"col-0-2":1673424000000,"col-1-1":152},{"col-0-2":1673510400000,"col-1-1":152},{"col-0-2":1673596800000,"col-1-1":151},{"col-0-2":1673683200000,"col-1-1":157},{"col-0-2":1673769600000,"col-1-1":151},{"col-0-2":1673856000000,"col-1-1":152},{"col-0-2":1673942400000,"col-1-1":142},{"col-0-2":1674028800000,"col-1-1":151},{"col-0-2":1674115200000,"col-1-1":163},{"col-0-2":1674201600000,"col-1-1":156},{"col-0-2":1674288000000,"col-1-1":153},{"col-0-2":1674374400000,"col-1-1":162},{"col-0-2":1674460800000,"col-1-1":152},{"col-0-2":1674547200000,"col-1-1":159},{"col-0-2":1674633600000,"col-1-1":165},{"col-0-2":1674720000000,"col-1-1":153},{"col-0-2":1674806400000,"col-1-1":149},{"col-0-2":1674892800000,"col-1-1":94}],"columns":[{"id":"col-0-2","name":"order_date per day","meta":{"type":"date_histogram","indexPatternId":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","aggConfigParams":{"field":"order_date","timeRange":{"from":"now-90d","to":"now"},"useNormalizedOpenSearchInterval":true,"scaleMetricValues":false,"interval":"auto","drop_partials":false,"min_doc_count":1,"extended_bounds":{}}}},{"id":"col-1-1","name":"Count","meta":{"type":"count","indexPatternId":"ff959d40-b880-11e8-a6d9-e546fe2bba5f","aggConfigParams":{}}}]}'; +export const simpleVisParams = + '{"addLegend":true,"addTimeMarker":false,"addTooltip":true,"categoryAxes":[{"id":"CategoryAxis-1","labels":{"filter":true,"show":true,"truncate":100},"position":"bottom","scale":{"type":"linear"},"show":true,"style":{},"title":{},"type":"category"}],"grid":{"categoryLines":false},"labels":{},"legendPosition":"right","seriesParams":[{"data":{"id":"1","label":"Count"},"drawLinesBetweenPoints":true,"interpolate":"linear","lineWidth":2,"mode":"normal","show":true,"showCircles":true,"type":"line","valueAxis":"ValueAxis-1"}],"thresholdLine":{"color":"#E7664C","show":false,"style":"full","value":10,"width":1},"times":[],"type":"line","valueAxes":[{"id":"ValueAxis-1","labels":{"filter":false,"rotate":0,"show":true,"truncate":100},"name":"LeftAxis-1","position":"left","scale":{"mode":"normal","type":"linear"},"show":true,"style":{},"title":{"text":"Count"},"type":"value"}]}'; +export const simpleDimensions = + '{"x":{"accessor":0,"format":{"id":"date","params":{"pattern":"YYYY-MM-DD"}},"params":{"date":true,"interval":"P1D","intervalESValue":1,"intervalESUnit":"d","format":"YYYY-MM-DD","bounds":{"min":"2022-11-18T00:14:09.617Z","max":"2023-02-16T00:14:09.617Z"}},"label":"order_date per day","aggType":"date_histogram"},"y":[{"accessor":1,"format":{"id":"number"},"params":{},"label":"Count","aggType":"count"}]}'; diff --git a/src/plugins/vis_type_vega/public/expressions/__mocks__/index.ts b/src/plugins/vis_type_vega/public/expressions/__mocks__/index.ts new file mode 100644 index 000000000000..0e8ad44d2bd7 --- /dev/null +++ b/src/plugins/vis_type_vega/public/expressions/__mocks__/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './helpers'; diff --git a/src/plugins/vis_type_vega/public/expressions/__snapshots__/helpers.test.js.snap b/src/plugins/vis_type_vega/public/expressions/__snapshots__/helpers.test.js.snap new file mode 100644 index 000000000000..85552a05278d --- /dev/null +++ b/src/plugins/vis_type_vega/public/expressions/__snapshots__/helpers.test.js.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`helpers createSpecFromXYChartDatatable() build complicated line chart" 1`] = `"{\\"$schema\\":\\"https://vega.github.io/schema/vega-lite/v5.json\\",\\"data\\":{\\"values\\":[{\\"col-0-2\\":1672214400000,\\"col-1-1\\":44,\\"col-2-3\\":60.9375},{\\"col-0-2\\":1672300800000,\\"col-1-1\\":150,\\"col-2-3\\":82.5},{\\"col-0-2\\":1672387200000,\\"col-1-1\\":154,\\"col-2-3\\":79.5},{\\"col-0-2\\":1672473600000,\\"col-1-1\\":144,\\"col-2-3\\":75.875},{\\"col-0-2\\":1672560000000,\\"col-1-1\\":133,\\"col-2-3\\":259.25},{\\"col-0-2\\":1672646400000,\\"col-1-1\\":149,\\"col-2-3\\":90},{\\"col-0-2\\":1672732800000,\\"col-1-1\\":152,\\"col-2-3\\":79.0625},{\\"col-0-2\\":1672819200000,\\"col-1-1\\":144,\\"col-2-3\\":82.5},{\\"col-0-2\\":1672905600000,\\"col-1-1\\":166,\\"col-2-3\\":85.25},{\\"col-0-2\\":1672992000000,\\"col-1-1\\":151,\\"col-2-3\\":92},{\\"col-0-2\\":1673078400000,\\"col-1-1\\":143,\\"col-2-3\\":90.75},{\\"col-0-2\\":1673164800000,\\"col-1-1\\":148,\\"col-2-3\\":92},{\\"col-0-2\\":1673251200000,\\"col-1-1\\":146,\\"col-2-3\\":83.25},{\\"col-0-2\\":1673337600000,\\"col-1-1\\":137,\\"col-2-3\\":98},{\\"col-0-2\\":1673424000000,\\"col-1-1\\":152,\\"col-2-3\\":83.6875},{\\"col-0-2\\":1673510400000,\\"col-1-1\\":152,\\"col-2-3\\":83.6875},{\\"col-0-2\\":1673596800000,\\"col-1-1\\":151,\\"col-2-3\\":87.4375},{\\"col-0-2\\":1673683200000,\\"col-1-1\\":157,\\"col-2-3\\":63.75},{\\"col-0-2\\":1673769600000,\\"col-1-1\\":151,\\"col-2-3\\":81.5625},{\\"col-0-2\\":1673856000000,\\"col-1-1\\":152,\\"col-2-3\\":100.6875},{\\"col-0-2\\":1673942400000,\\"col-1-1\\":142,\\"col-2-3\\":98},{\\"col-0-2\\":1674028800000,\\"col-1-1\\":151,\\"col-2-3\\":100.8125},{\\"col-0-2\\":1674115200000,\\"col-1-1\\":163,\\"col-2-3\\":83.6875},{\\"col-0-2\\":1674201600000,\\"col-1-1\\":156,\\"col-2-3\\":85.8125},{\\"col-0-2\\":1674288000000,\\"col-1-1\\":153,\\"col-2-3\\":98},{\\"col-0-2\\":1674374400000,\\"col-1-1\\":162,\\"col-2-3\\":75.9375},{\\"col-0-2\\":1674460800000,\\"col-1-1\\":152,\\"col-2-3\\":113.375},{\\"col-0-2\\":1674547200000,\\"col-1-1\\":159,\\"col-2-3\\":73.625},{\\"col-0-2\\":1674633600000,\\"col-1-1\\":165,\\"col-2-3\\":72.8125},{\\"col-0-2\\":1674720000000,\\"col-1-1\\":153,\\"col-2-3\\":113.375},{\\"col-0-2\\":1674806400000,\\"col-1-1\\":149,\\"col-2-3\\":82.5},{\\"col-0-2\\":1674892800000,\\"col-1-1\\":94,\\"col-2-3\\":54}]},\\"config\\":{\\"view\\":{\\"stroke\\":null},\\"concat\\":{\\"spacing\\":0},\\"legend\\":{\\"orient\\":\\"bottom\\"},\\"kibana\\":{\\"hideWarnings\\":true}},\\"layer\\":[{\\"mark\\":{\\"type\\":\\"line\\",\\"interpolate\\":\\"linear\\",\\"strokeWidth\\":2,\\"point\\":true},\\"encoding\\":{\\"x\\":{\\"axis\\":{\\"title\\":\\"order_date per day\\",\\"grid\\":false},\\"field\\":\\"col-0-2\\",\\"type\\":\\"temporal\\"},\\"y\\":{\\"axis\\":{\\"title\\":\\"Count\\",\\"grid\\":true,\\"orient\\":\\"right\\",\\"labels\\":true,\\"labelAngle\\":75},\\"field\\":\\"col-1-1\\",\\"type\\":\\"quantitative\\"},\\"tooltip\\":[{\\"field\\":\\"col-0-2\\",\\"type\\":\\"temporal\\",\\"title\\":\\"order_date per day\\"},{\\"field\\":\\"col-1-1\\",\\"type\\":\\"quantitative\\",\\"title\\":\\"Count\\"}],\\"color\\":{\\"datum\\":\\"Count\\"}}},{\\"mark\\":{\\"type\\":\\"line\\",\\"interpolate\\":\\"linear\\",\\"strokeWidth\\":2,\\"point\\":true},\\"encoding\\":{\\"x\\":{\\"axis\\":{\\"title\\":\\"order_date per day\\",\\"grid\\":false},\\"field\\":\\"col-0-2\\",\\"type\\":\\"temporal\\"},\\"y\\":{\\"axis\\":{\\"title\\":\\"Count\\",\\"grid\\":true,\\"orient\\":\\"right\\",\\"labels\\":true,\\"labelAngle\\":75},\\"field\\":\\"col-2-3\\",\\"type\\":\\"quantitative\\"},\\"tooltip\\":[{\\"field\\":\\"col-0-2\\",\\"type\\":\\"temporal\\",\\"title\\":\\"order_date per day\\"},{\\"field\\":\\"col-2-3\\",\\"type\\":\\"quantitative\\",\\"title\\":\\"Max products.min_price\\"}],\\"color\\":{\\"datum\\":\\"Max products.min_price\\"}}},{\\"mark\\":\\"rule\\",\\"encoding\\":{\\"x\\":{\\"type\\":\\"temporal\\",\\"field\\":\\"now_field\\"},\\"color\\":{\\"value\\":\\"red\\"},\\"size\\":{\\"value\\":1}}},{\\"mark\\":{\\"type\\":\\"rule\\",\\"color\\":\\"#E7664C\\",\\"strokeDash\\":[8,8]},\\"encoding\\":{\\"y\\":{\\"datum\\":100}}}],\\"transform\\":[{\\"calculate\\":\\"now()\\",\\"as\\":\\"now_field\\"}]}"`; + +exports[`helpers createSpecFromXYChartDatatable() build empty chart if no x-axis is defined" 1`] = `"{\\"$schema\\":\\"https://vega.github.io/schema/vega-lite/v5.json\\",\\"data\\":{\\"values\\":[{\\"col-0-2\\":1672214400000,\\"col-1-1\\":44},{\\"col-0-2\\":1672300800000,\\"col-1-1\\":150},{\\"col-0-2\\":1672387200000,\\"col-1-1\\":154},{\\"col-0-2\\":1672473600000,\\"col-1-1\\":144},{\\"col-0-2\\":1672560000000,\\"col-1-1\\":133},{\\"col-0-2\\":1672646400000,\\"col-1-1\\":149},{\\"col-0-2\\":1672732800000,\\"col-1-1\\":152},{\\"col-0-2\\":1672819200000,\\"col-1-1\\":144},{\\"col-0-2\\":1672905600000,\\"col-1-1\\":166},{\\"col-0-2\\":1672992000000,\\"col-1-1\\":151},{\\"col-0-2\\":1673078400000,\\"col-1-1\\":143},{\\"col-0-2\\":1673164800000,\\"col-1-1\\":148},{\\"col-0-2\\":1673251200000,\\"col-1-1\\":146},{\\"col-0-2\\":1673337600000,\\"col-1-1\\":137},{\\"col-0-2\\":1673424000000,\\"col-1-1\\":152},{\\"col-0-2\\":1673510400000,\\"col-1-1\\":152},{\\"col-0-2\\":1673596800000,\\"col-1-1\\":151},{\\"col-0-2\\":1673683200000,\\"col-1-1\\":157},{\\"col-0-2\\":1673769600000,\\"col-1-1\\":151},{\\"col-0-2\\":1673856000000,\\"col-1-1\\":152},{\\"col-0-2\\":1673942400000,\\"col-1-1\\":142},{\\"col-0-2\\":1674028800000,\\"col-1-1\\":151},{\\"col-0-2\\":1674115200000,\\"col-1-1\\":163},{\\"col-0-2\\":1674201600000,\\"col-1-1\\":156},{\\"col-0-2\\":1674288000000,\\"col-1-1\\":153},{\\"col-0-2\\":1674374400000,\\"col-1-1\\":162},{\\"col-0-2\\":1674460800000,\\"col-1-1\\":152},{\\"col-0-2\\":1674547200000,\\"col-1-1\\":159},{\\"col-0-2\\":1674633600000,\\"col-1-1\\":165},{\\"col-0-2\\":1674720000000,\\"col-1-1\\":153},{\\"col-0-2\\":1674806400000,\\"col-1-1\\":149},{\\"col-0-2\\":1674892800000,\\"col-1-1\\":94}]},\\"config\\":{\\"view\\":{\\"stroke\\":null},\\"concat\\":{\\"spacing\\":0},\\"legend\\":{\\"orient\\":\\"right\\"},\\"kibana\\":{\\"hideWarnings\\":true}},\\"layer\\":[]}"`; + +exports[`helpers createSpecFromXYChartDatatable() build simple line chart" 1`] = `"{\\"$schema\\":\\"https://vega.github.io/schema/vega-lite/v5.json\\",\\"data\\":{\\"values\\":[{\\"col-0-2\\":1672214400000,\\"col-1-1\\":44},{\\"col-0-2\\":1672300800000,\\"col-1-1\\":150},{\\"col-0-2\\":1672387200000,\\"col-1-1\\":154},{\\"col-0-2\\":1672473600000,\\"col-1-1\\":144},{\\"col-0-2\\":1672560000000,\\"col-1-1\\":133},{\\"col-0-2\\":1672646400000,\\"col-1-1\\":149},{\\"col-0-2\\":1672732800000,\\"col-1-1\\":152},{\\"col-0-2\\":1672819200000,\\"col-1-1\\":144},{\\"col-0-2\\":1672905600000,\\"col-1-1\\":166},{\\"col-0-2\\":1672992000000,\\"col-1-1\\":151},{\\"col-0-2\\":1673078400000,\\"col-1-1\\":143},{\\"col-0-2\\":1673164800000,\\"col-1-1\\":148},{\\"col-0-2\\":1673251200000,\\"col-1-1\\":146},{\\"col-0-2\\":1673337600000,\\"col-1-1\\":137},{\\"col-0-2\\":1673424000000,\\"col-1-1\\":152},{\\"col-0-2\\":1673510400000,\\"col-1-1\\":152},{\\"col-0-2\\":1673596800000,\\"col-1-1\\":151},{\\"col-0-2\\":1673683200000,\\"col-1-1\\":157},{\\"col-0-2\\":1673769600000,\\"col-1-1\\":151},{\\"col-0-2\\":1673856000000,\\"col-1-1\\":152},{\\"col-0-2\\":1673942400000,\\"col-1-1\\":142},{\\"col-0-2\\":1674028800000,\\"col-1-1\\":151},{\\"col-0-2\\":1674115200000,\\"col-1-1\\":163},{\\"col-0-2\\":1674201600000,\\"col-1-1\\":156},{\\"col-0-2\\":1674288000000,\\"col-1-1\\":153},{\\"col-0-2\\":1674374400000,\\"col-1-1\\":162},{\\"col-0-2\\":1674460800000,\\"col-1-1\\":152},{\\"col-0-2\\":1674547200000,\\"col-1-1\\":159},{\\"col-0-2\\":1674633600000,\\"col-1-1\\":165},{\\"col-0-2\\":1674720000000,\\"col-1-1\\":153},{\\"col-0-2\\":1674806400000,\\"col-1-1\\":149},{\\"col-0-2\\":1674892800000,\\"col-1-1\\":94}]},\\"config\\":{\\"view\\":{\\"stroke\\":null},\\"concat\\":{\\"spacing\\":0},\\"legend\\":{\\"orient\\":\\"right\\"},\\"kibana\\":{\\"hideWarnings\\":true}},\\"layer\\":[{\\"mark\\":{\\"type\\":\\"line\\",\\"interpolate\\":\\"linear\\",\\"strokeWidth\\":2,\\"point\\":true},\\"encoding\\":{\\"x\\":{\\"axis\\":{\\"title\\":\\"order_date per day\\",\\"grid\\":false},\\"field\\":\\"col-0-2\\",\\"type\\":\\"temporal\\"},\\"y\\":{\\"axis\\":{\\"title\\":\\"Count\\",\\"grid\\":false,\\"orient\\":\\"left\\",\\"labels\\":true,\\"labelAngle\\":0},\\"field\\":\\"col-1-1\\",\\"type\\":\\"quantitative\\"},\\"tooltip\\":[{\\"field\\":\\"col-0-2\\",\\"type\\":\\"temporal\\",\\"title\\":\\"order_date per day\\"},{\\"field\\":\\"col-1-1\\",\\"type\\":\\"quantitative\\",\\"title\\":\\"Count\\"}],\\"color\\":{\\"datum\\":\\"Count\\"}}}]}"`; diff --git a/src/plugins/vis_type_vega/public/expressions/helpers.test.js b/src/plugins/vis_type_vega/public/expressions/helpers.test.js new file mode 100644 index 000000000000..bf8bf28e9ca6 --- /dev/null +++ b/src/plugins/vis_type_vega/public/expressions/helpers.test.js @@ -0,0 +1,235 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + buildLayerMark, + buildXAxis, + buildYAxis, + cleanString, + createSpecFromXYChartDatatable, + formatDatatable, + setupConfig, +} from './helpers'; +import { + complexDatatable, + complexVisParams, + complexDimensions, + simpleDatatable, + simpleVisParams, + simpleDimensions, + noXAxisDimensions, +} from './__mocks__'; +import { + TEST_DATATABLE_NO_VIS_LAYERS, + TEST_DATATABLE_NO_VIS_LAYERS_DIRTY, +} from '../../../vis_augmenter/public'; + +describe('helpers', function () { + describe('formatDatatable()', function () { + it('formatSimpleDatatable', function () { + expect(formatDatatable(TEST_DATATABLE_NO_VIS_LAYERS)).toBe(TEST_DATATABLE_NO_VIS_LAYERS); + }); + it('formatDirtyDatatable', function () { + expect(formatDatatable(TEST_DATATABLE_NO_VIS_LAYERS_DIRTY)).toStrictEqual( + TEST_DATATABLE_NO_VIS_LAYERS + ); + }); + }); + + describe('cleanString()', function () { + it('string should not contain quotation marks', function () { + const dirtyString = '"someString"'; + expect(cleanString(dirtyString)).toBe('someString'); + }); + }); + + describe('setupConfig()', function () { + it('check all legend positions', function () { + const visAugmenterConfig = { + some: 'config', + }; + const baseConfig = { + view: { + stroke: null, + }, + concat: { + spacing: 0, + }, + legend: { + orient: null, + }, + kibana: { + hideWarnings: true, + visAugmenterConfig, + }, + }; + const positions = ['top', 'right', 'left', 'bottom']; + positions.forEach((position) => { + const visParams = { legendPosition: position }; + baseConfig.legend.orient = position; + baseConfig.legend.offset = position === 'top' || position === 'bottom' ? 0 : 18; + expect(setupConfig(visParams, visAugmenterConfig)).toStrictEqual(baseConfig); + }); + }); + }); + + describe('buildLayerMark()', function () { + const types = ['line', 'area', 'histogram']; + const interpolates = ['linear', 'cardinal', 'step-after']; + const strokeWidths = [-1, 0, 1, 2, 3, 4]; + const showCircles = [false, true]; + + it('check each mark possible value', function () { + const mark = { + type: null, + interpolate: null, + strokeWidth: null, + point: null, + }; + types.forEach((type) => { + mark.type = type; + interpolates.forEach((interpolate) => { + mark.interpolate = interpolate; + strokeWidths.forEach((strokeWidth) => { + mark.strokeWidth = strokeWidth; + showCircles.forEach((showCircle) => { + mark.point = showCircle; + const param = { + type: type, + interpolate: interpolate, + lineWidth: strokeWidth, + showCircles: showCircle, + }; + expect(buildLayerMark(param)).toStrictEqual(mark); + }); + }); + }); + }); + }); + }); + + describe('buildXAxis()', function () { + it('build different XAxis', function () { + const xAxisTitle = 'someTitle'; + const xAxisId = 'someId'; + [true, false].forEach((enableGrid) => { + const visParams = { grid: { categoryLines: enableGrid } }; + const vegaXAxis = { + axis: { + title: xAxisTitle, + grid: enableGrid, + }, + field: xAxisId, + type: 'temporal', + }; + expect(buildXAxis(xAxisTitle, xAxisId, visParams)).toStrictEqual(vegaXAxis); + }); + }); + }); + + describe('buildYAxis()', function () { + it('build different YAxis', function () { + const valueAxis = { + id: 'someId', + labels: { + rotate: 75, + show: false, + }, + position: 'left', + title: { + text: 'someText', + }, + }; + const column = { name: 'columnName', id: 'columnId' }; + const visParams = { grid: { valueAxis: true } }; + const vegaYAxis = { + axis: { + title: 'someText', + grid: true, + orient: 'left', + labels: false, + labelAngle: 75, + }, + field: 'columnId', + type: 'quantitative', + }; + expect(buildYAxis(column, valueAxis, visParams)).toStrictEqual(vegaYAxis); + + valueAxis.title.text = '""'; + vegaYAxis.axis.title = 'columnName'; + expect(buildYAxis(column, valueAxis, visParams)).toStrictEqual(vegaYAxis); + }); + it('build YAxis with percentile rank', function () { + const valueAxis = { + id: 'someId', + labels: { + rotate: 75, + show: false, + }, + position: 'left', + title: { + text: 'someText', + }, + }; + const column = { name: 'columnName', id: 'columnId', meta: { type: 'percentile_ranks' } }; + const visParams = { grid: { valueAxis: true } }; + const vegaYAxis = { + axis: { + title: 'someText', + grid: true, + orient: 'left', + labels: false, + labelAngle: 75, + format: '.0%', + }, + field: 'columnId', + type: 'quantitative', + }; + expect(buildYAxis(column, valueAxis, visParams)).toStrictEqual(vegaYAxis); + }); + }); + + describe('createSpecFromXYChartDatatable()', function () { + // Following 3 tests fail since they are persisting temporal data + // which can cause snapshots to fail depending on the test env they are run on. + // Tracking issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4555 + // TODO: Add a test for the fix in this PR: https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4554 + it.skip('build simple line chart"', function () { + expect( + JSON.stringify( + createSpecFromXYChartDatatable( + formatDatatable(JSON.parse(simpleDatatable)), + JSON.parse(simpleVisParams), + JSON.parse(simpleDimensions) + ) + ) + ).toMatchSnapshot(); + }); + + it.skip('build empty chart if no x-axis is defined"', function () { + expect( + JSON.stringify( + createSpecFromXYChartDatatable( + formatDatatable(JSON.parse(simpleDatatable)), + JSON.parse(simpleVisParams), + JSON.parse(noXAxisDimensions) + ) + ) + ).toMatchSnapshot(); + }); + + it.skip('build complicated line chart"', function () { + expect( + JSON.stringify( + createSpecFromXYChartDatatable( + formatDatatable(JSON.parse(complexDatatable)), + JSON.parse(complexVisParams), + JSON.parse(complexDimensions) + ) + ) + ).toMatchSnapshot(); + }); + }); +}); diff --git a/src/plugins/vis_type_vega/public/expressions/helpers.ts b/src/plugins/vis_type_vega/public/expressions/helpers.ts new file mode 100644 index 000000000000..5f65fe5f5bd7 --- /dev/null +++ b/src/plugins/vis_type_vega/public/expressions/helpers.ts @@ -0,0 +1,286 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + OpenSearchDashboardsDatatable, + OpenSearchDashboardsDatatableColumn, + OpenSearchDashboardsDatatableRow, +} from '../../../expressions/public'; +import { VislibDimensions, VisParams } from '../../../visualizations/public'; +import { isVisLayerColumn, VisAugmenterEmbeddableConfig } from '../../../vis_augmenter/public'; + +// TODO: move this to the visualization plugin that has VisParams once all of these parameters have been better defined +interface ValueAxis { + id: string; + labels: { + filter: boolean; + rotate: number; + show: boolean; + truncate: number; + }; + name: string; + position: string; + scale: { + mode: string; + type: string; + }; + show: true; + style: any; + title: { + text: string; + }; + type: string; +} + +export interface YAxisConfig { + minExtent: number; + maxExtent: number; + offset: number; + translate: number; + domainWidth: number; + labelPadding: number; + titlePadding: number; + tickOffset: number; + tickSize: number; +} + +// Get the first xaxis field as only 1 setup of X Axis will be supported and +// there won't be support for split series and split chart +const getXAxisId = (dimensions: any, columns: OpenSearchDashboardsDatatableColumn[]): string => { + return columns.filter((column) => column.name === dimensions.x.label)[0].id; +}; + +export const cleanString = (rawString: string): string => { + return rawString.replaceAll('"', ''); +}; + +// When using autosize features of vega-lite, the chart is expected to reposition +// correctly such that there is space for the chart and legend within the canvas. +// This works for horizontal positions (left/right), but breaks for vertical positions +// (top/bottom). To make up for this, we set the offset to 0 for these positions such that +// the chart will not get truncated or potentially cut off within the canvas. +export const calculateLegendOffset = (legendPosition: string): number => + // 18 is the default offset as of vega lite 5 + legendPosition === 'top' || legendPosition === 'bottom' ? 0 : 18; + +export const formatDatatable = ( + datatable: OpenSearchDashboardsDatatable +): OpenSearchDashboardsDatatable => { + datatable.columns.forEach((column) => { + // clean quotation marks from names in columns + column.name = cleanString(column.name); + // clean ids to remove "." as that will cause vega to not process it correctly. + // This happens for different metric types + column.id = column.id.replaceAll('.', '-'); + }); + + // clean row keys to remove "." as that will cause vega to not process it correctly + const updatedRows: OpenSearchDashboardsDatatableRow[] = datatable.rows.map((row) => + Object.entries(row).reduce((updatedRow, [key, value]) => { + const cleanKey = key.replaceAll('.', '-'); + return Object.assign(updatedRow, { [cleanKey]: value }); + }, {}) + ); + + datatable.rows = updatedRows; + return datatable; +}; + +export const setupConfig = (visParams: VisParams, config: VisAugmenterEmbeddableConfig) => { + const legendPosition = visParams.legendPosition; + return { + view: { + stroke: null, + }, + concat: { + spacing: 0, + }, + legend: { + orient: legendPosition, + offset: calculateLegendOffset(legendPosition), + }, + // This is parsed in the VegaParser and hides unnecessary warnings. + // For example, 'infinite extent' warnings that cover the chart + // when there is empty data for a time series + kibana: { + hideWarnings: true, + visAugmenterConfig: config, + }, + }; +}; + +export const buildLayerMark = (seriesParams: { + type: string; + interpolate: string; + lineWidth: number; + showCircles: boolean; +}) => { + return { + // Possible types are: line, area, histogram. The eligibility checker will + // prevent area and histogram (though area works in vega-lite) + type: seriesParams.type, + // Possible types: linear, cardinal, step-after. All of these types work in vega-lite + interpolate: seriesParams.interpolate, + // The possible values is any number, which matches what vega-lite supports + strokeWidth: seriesParams.lineWidth, + // this corresponds to showing the dots in the visbuilder for each data point + point: seriesParams.showCircles, + }; +}; + +export const buildXAxis = (xAxisTitle: string, xAxisId: string, visParams: VisParams) => { + return { + axis: { + title: xAxisTitle, + grid: visParams.grid.categoryLines, + }, + field: xAxisId, + // Right now, the line charts can only set the x-axis value to be a date attribute, so + // this should always be of type temporal + type: 'temporal', + }; +}; + +export const buildYAxis = ( + column: OpenSearchDashboardsDatatableColumn, + valueAxis: ValueAxis, + visParams: VisParams +) => { + const subAxis = { + title: cleanString(valueAxis.title.text) || column.name, + grid: visParams.grid.valueAxis !== undefined, + orient: valueAxis.position, + labels: valueAxis.labels.show, + labelAngle: valueAxis.labels.rotate, + }; + // Percentile ranks aggregation metric needs percentile formatting. + if (column.meta?.type === 'percentile_ranks') Object.assign(subAxis, { format: '.0%' }); + return { + axis: subAxis, + field: column.id, + type: 'quantitative', + }; +}; + +const isXAxisColumn = (column: OpenSearchDashboardsDatatableColumn): boolean => { + return column.meta?.aggConfigParams?.interval !== undefined; +}; + +// Given a chart's underlying datatable, generate a vega-lite spec. +// Designed to be used with x-y / temporal visualizations only. +export const createSpecFromXYChartDatatable = ( + datatable: OpenSearchDashboardsDatatable, + visParams: VisParams, + dimensions: VislibDimensions, + config: VisAugmenterEmbeddableConfig +): object => { + // TODO: we can try to use VegaSpec type but it is currently very outdated, where many + // of the fields and sub-fields don't have other optional params that we want for customizing. + // For now, we make this more loosely-typed by just specifying it as a generic object. + const spec = {} as any; + + spec.$schema = 'https://vega.github.io/schema/vega-lite/v5.json'; + spec.data = { + values: datatable.rows, + }; + spec.config = setupConfig(visParams, config); + + // Get the valueAxes data and generate a map to easily fetch the different valueAxes data + const valueAxis = new Map(); + visParams?.valueAxes?.forEach((yAxis: ValueAxis) => { + valueAxis.set(yAxis.id, yAxis); + }); + + spec.layer = [] as any[]; + + if (datatable.rows.length > 0 && dimensions.x !== null) { + const xAxisId = getXAxisId(dimensions, datatable.columns); + const xAxisTitle = cleanString(dimensions.x.label); + datatable.columns.forEach((column, index) => { + // Ignore columns that are for the x-axis and visLayers + if (isXAxisColumn(column) || isVisLayerColumn(column)) return; + // Get the series param id which is the 2nd value in the column id + // Example: 'col-1-3', the seriesParamId is 3. 'col-1-2-6', the seriesParamId is 2. + const seriesParamsId = column.id.split('-')[2]; + const currentSeriesParams = visParams.seriesParams.find( + (param: { data: { id: string } }) => param?.data?.id === seriesParamsId + ); + if (!currentSeriesParams) { + // eslint-disable-next-line no-console + console.error(`Failed to find matching series param for column of id: ${column.id}`); + return; + } + const currentValueAxis = valueAxis.get(currentSeriesParams.valueAxis.toString()); + let tooltip: Array<{ field: string; type: string; title: string }> = []; + if (visParams.addTooltip) { + tooltip = [ + { field: xAxisId, type: 'temporal', title: xAxisTitle }, + { field: column.id, type: 'quantitative', title: column.name }, + ]; + } + spec.layer.push({ + mark: buildLayerMark(currentSeriesParams), + encoding: { + x: buildXAxis(xAxisTitle, xAxisId, visParams), + y: buildYAxis(column, currentValueAxis, visParams), + tooltip, + color: { + // This ensures all the different metrics have their own distinct and unique color + datum: column.name, + }, + }, + }); + }); + } + + if (visParams.addTimeMarker) { + spec.transform = [ + { + calculate: 'now()', + as: 'now_field', + }, + ]; + + spec.layer.push({ + mark: 'rule', + encoding: { + x: { + type: 'temporal', + field: 'now_field', + }, + // The time marker on vislib is red, so keeping this consistent + color: { + value: 'red', + }, + size: { + value: 1, + }, + }, + }); + } + + if (visParams.thresholdLine.show as boolean) { + const layer = { + mark: { + type: 'rule', + color: visParams.thresholdLine.color, + strokeDash: [1, 0], + }, + encoding: { + y: { + datum: visParams.thresholdLine.value, + }, + }, + }; + + // Can only support making a threshold line with full or dashed style, but not dot-dashed + // due to vega-lite limitations + if (visParams.thresholdLine.style !== 'full') { + layer.mark.strokeDash = [8, 8]; + } + spec.layer.push(layer); + } + return spec; +}; diff --git a/src/plugins/vis_type_vega/public/expressions/index.ts b/src/plugins/vis_type_vega/public/expressions/index.ts new file mode 100644 index 000000000000..e85f175d55c6 --- /dev/null +++ b/src/plugins/vis_type_vega/public/expressions/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { LineVegaSpecExpressionFunctionDefinition } from './line_vega_spec_fn'; +export { VegaExpressionFunctionDefinition } from './vega_fn'; +export { YAxisConfig } from './helpers'; diff --git a/src/plugins/vis_type_vega/public/expressions/line_vega_spec_fn.ts b/src/plugins/vis_type_vega/public/expressions/line_vega_spec_fn.ts new file mode 100644 index 000000000000..63ea59114052 --- /dev/null +++ b/src/plugins/vis_type_vega/public/expressions/line_vega_spec_fn.ts @@ -0,0 +1,107 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { cloneDeep, isEmpty } from 'lodash'; +import { i18n } from '@osd/i18n'; +import { + ExpressionFunctionDefinition, + OpenSearchDashboardsDatatable, +} from '../../../expressions/public'; +import { VislibDimensions, VisParams } from '../../../visualizations/public'; +import { + VisLayer, + VisLayers, + PointInTimeEventsVisLayer, + isPointInTimeEventsVisLayer, + addPointInTimeEventsLayersToTable, + addPointInTimeEventsLayersToSpec, + enableVisLayersInSpecConfig, + addVisEventSignalsToSpecConfig, + augmentEventChartSpec, +} from '../../../vis_augmenter/public'; +import { formatDatatable, createSpecFromXYChartDatatable } from './helpers'; +import { VegaVisualizationDependencies } from '../plugin'; + +type Input = OpenSearchDashboardsDatatable; +type Output = Promise; + +interface Arguments { + visLayers: string | null; + visParams: string; + dimensions: string; + visAugmenterConfig: string; +} + +export type LineVegaSpecExpressionFunctionDefinition = ExpressionFunctionDefinition< + 'line_vega_spec', + Input, + Arguments, + Output +>; + +export const createLineVegaSpecFn = ( + dependencies: VegaVisualizationDependencies +): LineVegaSpecExpressionFunctionDefinition => ({ + name: 'line_vega_spec', + type: 'string', + inputTypes: ['opensearch_dashboards_datatable'], + help: i18n.translate('visTypeVega.function.help', { + defaultMessage: 'Construct line vega spec', + }), + args: { + visLayers: { + types: ['string', 'null'], + default: '', + help: '', + }, + visParams: { + types: ['string'], + default: '""', + help: '', + }, + dimensions: { + types: ['string'], + default: '""', + help: '', + }, + visAugmenterConfig: { + types: ['string'], + default: '""', + help: '', + }, + }, + async fn(input, args, context) { + let table = formatDatatable(cloneDeep(input)); + + const visParams = JSON.parse(args.visParams) as VisParams; + const dimensions = JSON.parse(args.dimensions) as VislibDimensions; + const allVisLayers = (args.visLayers ? JSON.parse(args.visLayers) : []) as VisLayers; + const visAugmenterConfig = JSON.parse(args.visAugmenterConfig); + + // currently only supporting PointInTimeEventsVisLayer type + const pointInTimeEventsVisLayers = allVisLayers.filter((visLayer: VisLayer) => + isPointInTimeEventsVisLayer(visLayer) + ) as PointInTimeEventsVisLayer[]; + + if (!isEmpty(pointInTimeEventsVisLayers) && dimensions.x !== null) { + table = addPointInTimeEventsLayersToTable(table, dimensions, pointInTimeEventsVisLayers); + } + + let spec = createSpecFromXYChartDatatable(table, visParams, dimensions, visAugmenterConfig); + + if (!isEmpty(pointInTimeEventsVisLayers) && dimensions.x !== null) { + spec = addPointInTimeEventsLayersToSpec(table, dimensions, spec); + // @ts-ignore + spec.config = enableVisLayersInSpecConfig(spec, pointInTimeEventsVisLayers); + // @ts-ignore + spec.config = addVisEventSignalsToSpecConfig(spec); + } + + // Apply other formatting changes to the spec (show vis data, hide axes, etc.) based on the + // vis augmenter config. Mostly used for customizing the views on the view events flyout. + spec = augmentEventChartSpec(visAugmenterConfig, spec); + return JSON.stringify(spec); + }, +}); diff --git a/src/plugins/vis_type_vega/public/vega_fn.ts b/src/plugins/vis_type_vega/public/expressions/vega_fn.ts similarity index 81% rename from src/plugins/vis_type_vega/public/vega_fn.ts rename to src/plugins/vis_type_vega/public/expressions/vega_fn.ts index abe2d3665ed3..6043b851a35c 100644 --- a/src/plugins/vis_type_vega/public/vega_fn.ts +++ b/src/plugins/vis_type_vega/public/expressions/vega_fn.ts @@ -35,13 +35,13 @@ import { ExpressionFunctionDefinition, OpenSearchDashboardsContext, Render, -} from '../../expressions/public'; -import { VegaVisualizationDependencies } from './plugin'; -import { createVegaRequestHandler } from './vega_request_handler'; -import { VegaInspectorAdapters } from './vega_inspector/index'; -import { TimeRange, Query } from '../../data/public'; -import { VisRenderValue } from '../../visualizations/public'; -import { VegaParser } from './data_model/vega_parser'; +} from '../../../expressions/public'; +import { VegaVisualizationDependencies } from '../plugin'; +import { createVegaRequestHandler } from '../vega_request_handler'; +import { VegaInspectorAdapters } from '../vega_inspector'; +import { TimeRange, Query } from '../../../data/public'; +import { VisRenderValue } from '../../../visualizations/public'; +import { VegaParser } from '../data_model/vega_parser'; type Input = OpenSearchDashboardsContext | null; type Output = Promise>; @@ -50,7 +50,17 @@ interface Arguments { spec: string; } -export type VisParams = Required; +export interface VisParams { + spec: string; +} + +export type VegaExpressionFunctionDefinition = ExpressionFunctionDefinition< + 'vega', + Input, + Arguments, + Output, + ExecutionContext +>; interface RenderValue extends VisRenderValue { visData: VegaParser; @@ -60,13 +70,7 @@ interface RenderValue extends VisRenderValue { export const createVegaFn = ( dependencies: VegaVisualizationDependencies -): ExpressionFunctionDefinition< - 'vega', - Input, - Arguments, - Output, - ExecutionContext -> => ({ +): VegaExpressionFunctionDefinition => ({ name: 'vega', type: 'render', inputTypes: ['opensearch_dashboards_context', 'null'], diff --git a/src/plugins/vis_type_vega/public/index.ts b/src/plugins/vis_type_vega/public/index.ts index c41add63d681..da9b8b396dba 100644 --- a/src/plugins/vis_type_vega/public/index.ts +++ b/src/plugins/vis_type_vega/public/index.ts @@ -35,3 +35,5 @@ import { VegaPlugin as Plugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { return new Plugin(initializerContext); } + +export * from './expressions'; diff --git a/src/plugins/vis_type_vega/public/plugin.ts b/src/plugins/vis_type_vega/public/plugin.ts index 64ab81eedfd2..3967c5351367 100644 --- a/src/plugins/vis_type_vega/public/plugin.ts +++ b/src/plugins/vis_type_vega/public/plugin.ts @@ -43,13 +43,16 @@ import { setInjectedMetadata, } from './services'; -import { createVegaFn } from './vega_fn'; +import { createVegaFn } from './expressions/vega_fn'; import { createVegaTypeDefinition } from './vega_type'; import { IServiceSettings } from '../../maps_legacy/public'; import './index.scss'; import { ConfigSchema } from '../config'; import { getVegaInspectorView } from './vega_inspector'; +import { createLineVegaSpecFn } from './expressions/line_vega_spec_fn'; +import { UiActionsStart } from '../../ui_actions/public'; +import { setUiActions } from './services'; /** @internal */ export interface VegaVisualizationDependencies { @@ -72,6 +75,7 @@ export interface VegaPluginSetupDependencies { /** @internal */ export interface VegaPluginStartDependencies { data: DataPublicPluginStart; + uiActions: UiActionsStart; } /** @internal */ @@ -104,13 +108,15 @@ export class VegaPlugin implements Plugin, void> { inspector.registerView(getVegaInspectorView({ uiSettings: core.uiSettings })); expressions.registerFunction(() => createVegaFn(visualizationDependencies)); + expressions.registerFunction(() => createLineVegaSpecFn(visualizationDependencies)); visualizations.createBaseVisualization(createVegaTypeDefinition(visualizationDependencies)); } - public start(core: CoreStart, { data }: VegaPluginStartDependencies) { + public start(core: CoreStart, { data, uiActions }: VegaPluginStartDependencies) { setNotifications(core.notifications); setData(data); + setUiActions(uiActions); setInjectedMetadata(core.injectedMetadata); } } diff --git a/src/plugins/vis_type_vega/public/services.ts b/src/plugins/vis_type_vega/public/services.ts index d241b66d472c..b67a0959c63d 100644 --- a/src/plugins/vis_type_vega/public/services.ts +++ b/src/plugins/vis_type_vega/public/services.ts @@ -33,6 +33,7 @@ import { CoreStart, NotificationsStart, IUiSettingsClient } from 'src/core/publi import { DataPublicPluginStart } from '../../data/public'; import { createGetterSetter } from '../../opensearch_dashboards_utils/public'; import { MapsLegacyConfig } from '../../maps_legacy/config'; +import { UiActionsStart } from '../../ui_actions/public'; export const [getData, setData] = createGetterSetter('Data'); @@ -40,6 +41,8 @@ export const [getNotifications, setNotifications] = createGetterSetter('UIActions'); + export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); export const [getInjectedMetadata, setInjectedMetadata] = createGetterSetter< diff --git a/src/plugins/vis_type_vega/public/vega_request_handler.ts b/src/plugins/vis_type_vega/public/vega_request_handler.ts index 7878e97d5889..7711f5d0f497 100644 --- a/src/plugins/vis_type_vega/public/vega_request_handler.ts +++ b/src/plugins/vis_type_vega/public/vega_request_handler.ts @@ -34,7 +34,7 @@ import { SearchAPI } from './data_model/search_api'; import { TimeCache } from './data_model/time_cache'; import { VegaVisualizationDependencies } from './plugin'; -import { VisParams } from './vega_fn'; +import { VisParams } from './expressions/vega_fn'; import { getData, getInjectedMetadata } from './services'; import { VegaInspectorAdapters } from './vega_inspector'; diff --git a/src/plugins/vis_type_vega/public/vega_type.ts b/src/plugins/vis_type_vega/public/vega_type.ts index 03fc05fdee89..8a95f5c1c79f 100644 --- a/src/plugins/vis_type_vega/public/vega_type.ts +++ b/src/plugins/vis_type_vega/public/vega_type.ts @@ -74,7 +74,7 @@ export const createVegaTypeDefinition = ( showFilterBar: true, }, getSupportedTriggers: () => { - return [VIS_EVENT_TO_TRIGGER.applyFilter]; + return [VIS_EVENT_TO_TRIGGER.applyFilter, VIS_EVENT_TO_TRIGGER.externalAction]; }, getUsedIndexPattern: async (visParams) => { try { diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js b/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js index 657bd04403e6..71a7dd6cb48d 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js +++ b/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js @@ -51,6 +51,7 @@ const vegaFunctions = { opensearchDashboardsRemoveFilter: 'removeFilterHandler', opensearchDashboardsRemoveAllFilters: 'removeAllFiltersHandler', opensearchDashboardsSetTimeFilter: 'setTimeFilterHandler', + opensearchDashboardsVisEventTriggered: 'triggerExternalActionHandler', }; for (const funcName of Object.keys(vegaFunctions)) { @@ -76,6 +77,7 @@ export class VegaBaseView { this._serviceSettings = opts.serviceSettings; this._filterManager = opts.filterManager; this._applyFilter = opts.applyFilter; + this._triggerExternalAction = opts.externalAction; this._timefilter = opts.timefilter; this._view = null; this._vegaViewConfig = null; @@ -259,6 +261,25 @@ export class VegaBaseView { return false; } + // This is only used when the PointInTimeEventsVisLayer type in vega parser's + // visibleVisLayers is true. This VisLayer type is currently only supported + // for time series chart types. It may be updated + // in the future to expand to other chart type use cases. + // Because there is no clean way to use autosize for concatenated views, + // we manually set the value of the top view (the base vis) to fill in + // space and leave enough space to show the bottom view (the events vis). + // Ref: https://vega.github.io/vega-lite/docs/size.html#limitations + addPointInTimeEventPadding(view) { + // This value represents the pixel height of the event canvas. It is determined + // based on the event mark size, such that there is sufficient but minimal space + // needed to render the event marks. + const eventVisHeight = 100; + const height = Math.max(0, this._$container.height()) - eventVisHeight; + if (view._signals.concat_0_height !== undefined) { + view._signals.concat_0_height.value = height; + } + } + setView(view) { if (this._view === view) return; @@ -327,6 +348,18 @@ export class VegaBaseView { this._applyFilter({ filters: [filter] }); } + /** + * This method is triggered using signal expression in vega-spec via @see opensearchDashboardsVisEventTriggered + * @param {import('vega').ScenegraphEvent} event Event triggered by the underlying vega visualization. + * @param {import('vega').Item} datum Data associated with the element on which the event was triggered. + */ + triggerExternalActionHandler(event, datum) { + this._triggerExternalAction({ + event, + item: datum, + }); + } + /** * @param {object} query Query DSL snippet, as used in the query DSL editor * @param {string} [index] as defined in OpenSearch Dashboards, or default if missing @@ -442,7 +475,11 @@ export class VegaBaseView { * Set global debug variable to simplify vega debugging in console. Show info message first time */ setDebugValues(view, spec, vlspec) { - this._parser.searchAPI.inspectorAdapters?.vega.bindInspectValues({ + // The vega inspector can now be null when rendering line charts using vega for the overlay visualization feature. + // This is because the inspectors get added at bootstrap to the different chart types and visualize embeddable + // thinks the line chart is vislib line chart and uses that inspector adapter and has no way of knowing it's + // actually a vega-lite chart and needs to use the vega inspector adapter without hacky code. + this._parser.searchAPI.inspectorAdapters?.vega?.bindInspectValues({ view, spec: vlspec || spec, }); diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_view.js b/src/plugins/vis_type_vega/public/vega_view/vega_view.js index 45d15849ed47..9a1bc6bcb946 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_view.js +++ b/src/plugins/vis_type_vega/public/vega_view/vega_view.js @@ -28,6 +28,12 @@ * under the License. */ +import { get } from 'lodash'; +import { + VisLayerTypes, + calculateYAxisPadding, + VisFlyoutContext, +} from '../../../vis_augmenter/public'; import { vega } from '../lib/vega'; import { VegaBaseView } from './vega_base_view'; @@ -44,6 +50,60 @@ export class VegaView extends VegaBaseView { view.warn = this.onWarn.bind(this); view.error = this.onError.bind(this); if (this._parser.useResize) this.updateVegaSize(view); + + const showPointInTimeEvents = + this._parser.visibleVisLayers?.get(VisLayerTypes.PointInTimeEvents) === true; + + if (showPointInTimeEvents) { + this.addPointInTimeEventPadding(view); + const inFlyout = get(this, '_parser.visAugmenterConfig.inFlyout', false); + const flyoutContext = get( + this, + '_parser.visAugmenterConfig.flyoutContext', + VisFlyoutContext.BASE_VIS + ); + const leftValueAxisPadding = get( + this, + '_parser.visAugmenterConfig.leftValueAxisPadding', + false + ); + const rightValueAxisPadding = get( + this, + '_parser.visAugmenterConfig.rightValueAxisPadding', + false + ); + const yAxisConfig = get(this, '_parser.vlspec.config.axisY', {}); + + // Autosizing is needed here since autosize won't be set correctly when there is PointInTimeEventLayers. + // This is because these layers cause the spec to use `vconcat` under the hood to stack the base chart + // with the event chart. Autosize doesn't work at the vega-lite level, so we set here at the vega level. + // Details here: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/3485#issuecomment-1507442348 + view.autosize({ + type: 'fit', + contains: 'padding', + }); + + if (inFlyout) { + const yAxisPadding = calculateYAxisPadding(yAxisConfig); + view.padding({ + ...view.padding(), + // If we are displaying an event chart (no vis data), then we need to offset the chart + // to align the data / events. We do this by checking if padding is needed on the left + // and/or right, and adding padding based on the y axis config. + left: + leftValueAxisPadding && + (flyoutContext === VisFlyoutContext.EVENT_VIS || + flyoutContext === VisFlyoutContext.TIMELINE_VIS) + ? yAxisPadding + : 0, + right: + rightValueAxisPadding && flyoutContext === VisFlyoutContext.EVENT_VIS + ? yAxisPadding + : 0, + }); + } + } + view.initialize(this._$container.get(0), this._$controls.get(0)); if (this._parser.useHover) view.hover(); diff --git a/src/plugins/vis_type_vega/public/vega_visualization.js b/src/plugins/vis_type_vega/public/vega_visualization.js index af5c58f8a149..379670bda413 100644 --- a/src/plugins/vis_type_vega/public/vega_visualization.js +++ b/src/plugins/vis_type_vega/public/vega_visualization.js @@ -90,6 +90,7 @@ export const createVegaVisualization = ({ getServiceSettings }) => serviceSettings, filterManager, timefilter, + externalAction: this._vis.API.events.externalAction, }; if (vegaParser.useMap) { diff --git a/src/plugins/vis_type_vislib/opensearch_dashboards.json b/src/plugins/vis_type_vislib/opensearch_dashboards.json index b0d9627bb10f..c498d121e99d 100644 --- a/src/plugins/vis_type_vislib/opensearch_dashboards.json +++ b/src/plugins/vis_type_vislib/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["charts", "data", "expressions", "visualizations", "opensearchDashboardsLegacy"], + "requiredPlugins": ["charts", "data", "expressions", "visualizations", "opensearchDashboardsLegacy", "visTypeVega"], "optionalPlugins": ["visTypeXy"], - "requiredBundles": ["opensearchDashboardsUtils", "visDefaultEditor"] + "requiredBundles": ["opensearchDashboardsUtils", "visDefaultEditor", "visAugmenter"] } diff --git a/src/plugins/vis_type_vislib/public/line.ts b/src/plugins/vis_type_vislib/public/line.ts index 06a5be4fe414..04ae732e2903 100644 --- a/src/plugins/vis_type_vislib/public/line.ts +++ b/src/plugins/vis_type_vislib/public/line.ts @@ -50,6 +50,7 @@ import { createVislibVisController } from './vis_controller'; import { VisTypeVislibDependencies } from './plugin'; import { Rotates } from '../../charts/public'; import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public'; +import { toExpressionAst } from './line_to_expression'; export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({ name: 'line', @@ -58,6 +59,7 @@ export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) => description: i18n.translate('visTypeVislib.line.lineDescription', { defaultMessage: 'Emphasize trends', }), + toExpressionAst, visualization: createVislibVisController(deps), getSupportedTriggers: () => { return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush]; diff --git a/src/plugins/vis_type_vislib/public/line_to_expression.ts b/src/plugins/vis_type_vislib/public/line_to_expression.ts new file mode 100644 index 000000000000..8650c6013801 --- /dev/null +++ b/src/plugins/vis_type_vislib/public/line_to_expression.ts @@ -0,0 +1,72 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { get } from 'lodash'; +import { buildVislibDimensions, Vis, VislibDimensions } from '../../visualizations/public'; +import { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { OpenSearchaggsExpressionFunctionDefinition } from '../../data/common/search/expressions'; +import { + VegaExpressionFunctionDefinition, + LineVegaSpecExpressionFunctionDefinition, +} from '../../vis_type_vega/public'; +import { isEligibleForVisLayers, VisAugmenterEmbeddableConfig } from '../../vis_augmenter/public'; + +export const toExpressionAst = async (vis: Vis, params: any) => { + // Construct the existing expr fns that are ran for vislib line chart, up until the render fn. + // That way we get the exact same data table of results as if it was a vislib chart. + const opensearchaggsFn = buildExpressionFunction( + 'opensearchaggs', + { + index: vis.data.indexPattern!.id!, + metricsAtAllLevels: vis.isHierarchical(), + partialRows: vis.params.showPartialRows || false, + aggConfigs: JSON.stringify(vis.data.aggs!.aggs), + includeFormatHints: false, + } + ); + + // Checks if there are vislayers to overlay. If not, default to the vislib implementation. + const dimensions: VislibDimensions = await buildVislibDimensions(vis, params); + if ( + params.visLayers == null || + Object.keys(params.visLayers).length === 0 || + !isEligibleForVisLayers(vis) + ) { + // Render using vislib instead of vega-lite + const visConfig = { ...vis.params, dimensions }; + const vislib = buildExpressionFunction('vislib', { + type: 'line', + visConfig: JSON.stringify(visConfig), + }); + const ast = buildExpression([opensearchaggsFn, vislib]); + return ast.toAst(); + } else { + const visAugmenterConfig = get( + params, + 'visAugmenterConfig', + {} + ) as VisAugmenterEmbeddableConfig; + + // adding the new expr fn here that takes the datatable and converts to a vega spec + const vegaSpecFn = buildExpressionFunction( + 'line_vega_spec', + { + visLayers: JSON.stringify(params.visLayers), + visParams: JSON.stringify(vis.params), + dimensions: JSON.stringify(dimensions), + visAugmenterConfig: JSON.stringify(visAugmenterConfig), + } + ); + const vegaSpecFnExpressionBuilder = buildExpression([vegaSpecFn]); + + // build vega expr fn. use nested expression fn syntax to first construct the + // spec via 'line_vega_spec' fn, then set as the arg for the final 'vega' fn + const vegaFn = buildExpressionFunction('vega', { + spec: vegaSpecFnExpressionBuilder, + }); + const ast = buildExpression([opensearchaggsFn, vegaFn]); + return ast.toAst(); + } +}; diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss b/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss index f5b93730fb75..c114c07f17b9 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/_legend.scss @@ -84,7 +84,7 @@ $visLegendLineHeight: $euiSize; } .visLegend__valueColorPicker { - width: ($euiSizeL * 8); // 8 columns + width: ($euiSizeL * 10); // 10 columns } .visLegend__valueColorPickerDot { diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx index 18192c3faa34..1038c663d0dc 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx @@ -35,7 +35,7 @@ import { I18nProvider } from '@osd/i18n/react'; import { EuiButtonGroup } from '@elastic/eui'; import { VisLegend, VisLegendProps } from './legend'; -import { legendColors } from './models'; +import { legendColors } from './legend_item'; jest.mock('@elastic/eui', () => { const original = jest.requireActual('@elastic/eui'); diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx index f6e79b74841c..b228f32c7596 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/legend_item.tsx @@ -42,9 +42,14 @@ import { EuiPopoverProps, EuiButtonGroup, EuiButtonGroupOptionProps, + euiPaletteColorBlind, } from '@elastic/eui'; -import { legendColors, LegendItem } from './models'; +import { LegendItem } from './models'; + +// starting from the default categorical colors, we generate 6 additional variants, +// 3 lighter and 3 darker +export const legendColors = euiPaletteColorBlind({ rotations: 7, direction: 'both' }); interface Props { item: LegendItem; diff --git a/src/plugins/vis_type_vislib/public/vislib/components/legend/models.ts b/src/plugins/vis_type_vislib/public/vislib/components/legend/models.ts index 1d86703b5c38..48a0cfc9b2af 100644 --- a/src/plugins/vis_type_vislib/public/vislib/components/legend/models.ts +++ b/src/plugins/vis_type_vislib/public/vislib/components/legend/models.ts @@ -34,62 +34,3 @@ export interface LegendItem { } export const CUSTOM_LEGEND_VIS_TYPES = ['heatmap', 'gauge']; - -export const legendColors: string[] = [ - '#3F6833', - '#967302', - '#2F575E', - '#99440A', - '#58140C', - '#052B51', - '#511749', - '#3F2B5B', // 6 - '#508642', - '#CCA300', - '#447EBC', - '#C15C17', - '#890F02', - '#0A437C', - '#6D1F62', - '#584477', // 2 - '#629E51', - '#E5AC0E', - '#64B0C8', - '#E0752D', - '#BF1B00', - '#0A50A1', - '#962D82', - '#614D93', // 4 - '#7EB26D', - '#EAB839', - '#6ED0E0', - '#EF843C', - '#E24D42', - '#1F78C1', - '#BA43A9', - '#705DA0', // Normal - '#9AC48A', - '#F2C96D', - '#65C5DB', - '#F9934E', - '#EA6460', - '#5195CE', - '#D683CE', - '#806EB7', // 5 - '#B7DBAB', - '#F4D598', - '#70DBED', - '#F9BA8F', - '#F29191', - '#82B5D8', - '#E5A8E2', - '#AEA2E0', // 3 - '#E0F9D7', - '#FCEACA', - '#CFFAFF', - '#F9E2D2', - '#FCE2DE', - '#BADFF4', - '#F9D9F9', - '#DEDAF7', // 7 -]; diff --git a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.test.js b/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.test.js index aa25c059ed28..1559050aaa3a 100644 --- a/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.test.js +++ b/src/plugins/vis_type_vislib/public/vislib/visualizations/gauge_chart.test.js @@ -155,11 +155,11 @@ describe('Vislib Gauge Chart Test Suite', function () { fills.push(this.style.fill); }); expect(fills).toEqual([ - 'rgb(165,0,38)', - 'rgb(255,255,190)', - 'rgb(255,255,190)', - 'rgb(0,104,55)', - 'rgb(0,104,55)', + 'rgb(189,39,30)', + 'rgb(245,167,0)', + 'rgb(245,167,0)', + 'rgb(1,125,115)', + 'rgb(1,125,115)', ]); }); @@ -175,11 +175,11 @@ describe('Vislib Gauge Chart Test Suite', function () { fills.push(this.style.fill); }); expect(fills).toEqual([ - 'rgb(8,48,107)', - 'rgb(107,174,214)', - 'rgb(107,174,214)', - 'rgb(247,251,255)', - 'rgb(247,251,255)', + 'rgb(96,146,192)', + 'rgb(178,199,223)', + 'rgb(178,199,223)', + 'rgb(255,255,255)', + 'rgb(255,255,255)', ]); }); }); diff --git a/src/plugins/visualizations/opensearch_dashboards.json b/src/plugins/visualizations/opensearch_dashboards.json index 6223ffce3808..b7c5e4ab9b4e 100644 --- a/src/plugins/visualizations/opensearch_dashboards.json +++ b/src/plugins/visualizations/opensearch_dashboards.json @@ -5,5 +5,5 @@ "ui": true, "requiredPlugins": ["data", "expressions", "uiActions", "embeddable", "inspector", "dashboard"], "optionalPlugins": ["usageCollection"], - "requiredBundles": ["opensearchDashboardsUtils", "discover", "savedObjects"] + "requiredBundles": ["opensearchDashboardsUtils", "discover", "savedObjects", "visAugmenter"] } diff --git a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts index 03666a199dca..2c937847ee61 100644 --- a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts +++ b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts @@ -44,6 +44,7 @@ import { getHttp, getTimeFilter, getCapabilities, + getSavedAugmentVisLoader, } from '../services'; import { VisualizeEmbeddableFactoryDeps } from './visualize_embeddable_factory'; import { VISUALIZE_ENABLE_LABS_SETTING } from '../../common/constants'; @@ -88,6 +89,8 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe const editable = getCapabilities().visualize.save as boolean; + const savedAugmentVisLoader = getSavedAugmentVisLoader(); + return new VisualizeEmbeddable( getTimeFilter(), { @@ -101,6 +104,7 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe input, attributeService, savedVisualizationsLoader, + savedAugmentVisLoader, parent ); } catch (e) { diff --git a/src/plugins/visualizations/public/embeddable/events.ts b/src/plugins/visualizations/public/embeddable/events.ts index 2a17ef9d5ef3..3d34cfe49959 100644 --- a/src/plugins/visualizations/public/embeddable/events.ts +++ b/src/plugins/visualizations/public/embeddable/events.ts @@ -32,16 +32,19 @@ import { APPLY_FILTER_TRIGGER, SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, + EXTERNAL_ACTION_TRIGGER, } from '../../../ui_actions/public'; export interface VisEventToTrigger { ['applyFilter']: typeof APPLY_FILTER_TRIGGER; ['brush']: typeof SELECT_RANGE_TRIGGER; ['filter']: typeof VALUE_CLICK_TRIGGER; + ['externalAction']: typeof EXTERNAL_ACTION_TRIGGER; } export const VIS_EVENT_TO_TRIGGER: VisEventToTrigger = { applyFilter: APPLY_FILTER_TRIGGER, brush: SELECT_RANGE_TRIGGER, filter: VALUE_CLICK_TRIGGER, + externalAction: EXTERNAL_ACTION_TRIGGER, }; diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index f3808951d519..28c0048cdedc 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -28,7 +28,7 @@ * under the License. */ -import _, { get } from 'lodash'; +import _, { get, isEmpty } from 'lodash'; import { Subscription } from 'rxjs'; import * as Rx from 'rxjs'; import { i18n } from '@osd/i18n'; @@ -57,13 +57,26 @@ import { } from '../../../expressions/public'; import { buildPipeline } from '../legacy/build_pipeline'; import { Vis, SerializedVis } from '../vis'; -import { getExpressions, getUiActions } from '../services'; +import { getExpressions, getNotifications, getUiActions } from '../services'; import { VIS_EVENT_TO_TRIGGER } from './events'; import { VisualizeEmbeddableFactoryDeps } from './visualize_embeddable_factory'; import { TriggerId } from '../../../ui_actions/public'; import { SavedObjectAttributes } from '../../../../core/types'; -import { AttributeService } from '../../../dashboard/public'; +import { AttributeService, DASHBOARD_CONTAINER_TYPE } from '../../../dashboard/public'; import { SavedVisualizationsLoader } from '../saved_visualizations'; +import { + SavedAugmentVisLoader, + ExprVisLayers, + VisLayers, + isEligibleForVisLayers, + getAugmentVisSavedObjs, + buildPipelineFromAugmentVisSavedObjs, + getAnyErrors, + AugmentVisContext, + VisLayer, + VisAugmenterEmbeddableConfig, + PLUGIN_RESOURCE_DELETE_TRIGGER, +} from '../../../vis_augmenter/public'; import { VisSavedObject } from '../types'; const getKeys = (o: T): Array => Object.keys(o) as Array; @@ -83,6 +96,11 @@ export interface VisualizeInput extends EmbeddableInput { }; savedVis?: SerializedVis; table?: unknown; + // TODO: This config, along with other VisAugmenter-related fields (visLayers, savedAugmentVisLoader) + // can be decoupled from embeddables plugin entirely. It is only used for changing the underlying + // visualization. Instead, we can use ReactExpressionRenderer for handling the rendering. + // For details, see https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4483 + visAugmenterConfig?: VisAugmenterEmbeddableConfig; } export interface VisualizeOutput extends EmbeddableOutput { @@ -114,7 +132,7 @@ export class VisualizeEmbeddable private visCustomizations?: Pick; private subscriptions: Subscription[] = []; private expression: string = ''; - private vis: Vis; + public vis: Vis; private domNode: any; public readonly type = VISUALIZE_EMBEDDABLE_TYPE; private autoRefreshFetchSubscription: Subscription; @@ -127,6 +145,9 @@ export class VisualizeEmbeddable VisualizeByReferenceInput >; private savedVisualizationsLoader?: SavedVisualizationsLoader; + private savedAugmentVisLoader?: SavedAugmentVisLoader; + public visLayers?: VisLayer[]; + private visAugmenterConfig?: VisAugmenterEmbeddableConfig; constructor( timefilter: TimefilterContract, @@ -138,6 +159,7 @@ export class VisualizeEmbeddable VisualizeByReferenceInput >, savedVisualizationsLoader?: SavedVisualizationsLoader, + savedAugmentVisLoader?: SavedAugmentVisLoader, parent?: IContainer ) { super( @@ -160,7 +182,8 @@ export class VisualizeEmbeddable this.vis.uiState.on('reload', this.reload); this.attributeService = attributeService; this.savedVisualizationsLoader = savedVisualizationsLoader; - + this.savedAugmentVisLoader = savedAugmentVisLoader; + this.visAugmenterConfig = initialInput.visAugmenterConfig; this.autoRefreshFetchSubscription = timefilter .getAutoRefreshFetch$() .subscribe(this.updateHandler.bind(this)); @@ -336,6 +359,10 @@ export class VisualizeEmbeddable timeFieldName: this.vis.data.indexPattern?.timeFieldName!, ...event.data, }; + } else if (triggerId === VIS_EVENT_TO_TRIGGER.externalAction) { + context = { + savedObjectId: this.vis.id, + } as AugmentVisContext; } else { context = { embeddable: this, @@ -393,10 +420,23 @@ export class VisualizeEmbeddable } this.abortController = new AbortController(); const abortController = this.abortController; + + // By waiting for this to complete, this.visLayers will be populated. + // Note we only fetch when in the context of a dashboard or in the view + // events flyout - we do not show events or have event functionality when + // in the vis edit view. + const shouldFetchVisLayers = + this.parent?.type === DASHBOARD_CONTAINER_TYPE || this.visAugmenterConfig?.inFlyout; + if (shouldFetchVisLayers) { + await this.populateVisLayers(); + } + this.expression = await buildPipeline(this.vis, { timefilter: this.timefilter, timeRange: this.timeRange, abortSignal: this.abortController!.signal, + visLayers: this.visLayers, + visAugmenterConfig: this.visAugmenterConfig, }); if (this.handler && !abortController.signal.aborted) { @@ -465,4 +505,89 @@ export class VisualizeEmbeddable { showSaveModal: true, saveModalTitle } ); }; + + /** + * Fetches any VisLayers, and filters out to only include ones in the list of + * input resource IDs, if specified. Assigns them to this.visLayers. + * Note this fn is public so we can fetch vislayers on demand when needed, + * e.g., generating other vis embeddables in the view events flyout. + */ + public async populateVisLayers(): Promise { + this.visLayers = await this.fetchVisLayers(); + } + + /** + * Collects any VisLayers from plugin expressions functions + * by fetching all AugmentVisSavedObjects that meets below criteria: + * - includes a reference to the vis saved object id + * - includes any of the plugin resource IDs, if specified + */ + fetchVisLayers = async (): Promise => { + try { + const expressionParams: IExpressionLoaderParams = { + searchContext: { + timeRange: this.timeRange, + query: this.input.query, + filters: this.input.filters, + }, + uiState: this.vis.uiState, + inspectorAdapters: this.inspectorAdapters, + }; + const aborted = get(this.abortController, 'signal.aborted', false) as boolean; + const augmentVisSavedObjs = await getAugmentVisSavedObjs( + this.vis.id, + this.savedAugmentVisLoader, + undefined, + this.visAugmenterConfig?.visLayerResourceIds + ); + + if (!isEmpty(augmentVisSavedObjs) && !aborted && isEligibleForVisLayers(this.vis)) { + const visLayersPipeline = buildPipelineFromAugmentVisSavedObjs(augmentVisSavedObjs); + // The initial input for the pipeline will just be an empty arr of VisLayers. As plugin + // expression functions are ran, they will incrementally append their generated VisLayers to it. + const visLayersPipelineInput = { + type: 'vis_layers', + layers: [] as VisLayers, + }; + // We cannot use this.handler in this case, since it does not support the run() cmd + // we need here. So, we consume the expressions service to run this directly instead. + const exprVisLayers = (await getExpressions().run( + visLayersPipeline, + visLayersPipelineInput, + expressionParams as Record + )) as ExprVisLayers; + const visLayers = exprVisLayers.layers; + + /** + * There may be some stale saved objs if any plugin resources have been deleted since last time + * data was fetched from them via the expression functions. Execute this trigger so any listening + * action can perform cleanup. + * + * TODO: this should be automatically handled by the saved objects plugin. Tracking issue: + * https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4499 + */ + getUiActions().getTrigger(PLUGIN_RESOURCE_DELETE_TRIGGER).exec({ + savedObjs: augmentVisSavedObjs, + visLayers, + }); + + const err = getAnyErrors(visLayers, this.vis.title); + // This is only true when one or more VisLayers has an error + if (err !== undefined) { + const { toasts } = getNotifications(); + toasts.addError(err, { + title: i18n.translate('visualizations.renderVisTitle', { + defaultMessage: `Error loading data on the ${this.vis.title} chart`, + }), + toastMessage: ' ', + id: this.id, + }); + } + return visLayers; + } + } catch { + return [] as VisLayers; + } + return [] as VisLayers; + }; } diff --git a/src/plugins/visualizations/public/expressions/vis.ts b/src/plugins/visualizations/public/expressions/vis.ts index acf747973dee..02f13ab2ad8d 100644 --- a/src/plugins/visualizations/public/expressions/vis.ts +++ b/src/plugins/visualizations/public/expressions/vis.ts @@ -55,6 +55,7 @@ export interface ExprVisAPIEvents { filter: (data: any) => void; brush: (data: any) => void; applyFilter: (data: any) => void; + externalAction: (data: any) => void; } export interface ExprVisAPI { @@ -99,6 +100,10 @@ export class ExprVis extends EventEmitter { if (!this.eventsSubject) return; this.eventsSubject.next({ name: 'applyFilter', data }); }, + externalAction: (data: any) => { + if (!this.eventsSubject) return; + this.eventsSubject.next({ name: 'externalAction', data }); + }, }, }; } diff --git a/src/plugins/visualizations/public/index.ts b/src/plugins/visualizations/public/index.ts index 46d3b3dd7d03..6c8cf4ec51d2 100644 --- a/src/plugins/visualizations/public/index.ts +++ b/src/plugins/visualizations/public/index.ts @@ -41,9 +41,18 @@ export function plugin(initializerContext: PluginInitializerContext) { /** @public static code */ export { Vis } from './vis'; export { TypesService } from './vis_types/types_service'; -export { VISUALIZE_EMBEDDABLE_TYPE, VIS_EVENT_TO_TRIGGER } from './embeddable'; +export { + VISUALIZE_EMBEDDABLE_TYPE, + VIS_EVENT_TO_TRIGGER, + VisualizeEmbeddable, + DisabledLabEmbeddable, +} from './embeddable'; export { VisualizationContainer, VisualizationNoResults } from './components'; -export { getSchemas as getVisSchemas, buildVislibDimensions } from './legacy/build_pipeline'; +export { + getSchemas as getVisSchemas, + buildVislibDimensions, + VislibDimensions, +} from './legacy/build_pipeline'; /** @public types */ export { VisualizationsSetup, VisualizationsStart }; @@ -67,3 +76,4 @@ export { export { ExprVisAPIEvents } from './expressions/vis'; export { VisualizationListItem } from './vis_types/vis_type_alias_registry'; export { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants'; +export { createSavedVisLoader } from './saved_visualizations'; diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.ts b/src/plugins/visualizations/public/legacy/build_pipeline.ts index 1cbb3bc38879..de41a7a48c02 100644 --- a/src/plugins/visualizations/public/legacy/build_pipeline.ts +++ b/src/plugins/visualizations/public/legacy/build_pipeline.ts @@ -33,6 +33,8 @@ import moment from 'moment'; import { formatExpression, SerializedFieldFormat } from '../../../../plugins/expressions/public'; import { IAggConfig, search, TimefilterContract } from '../../../../plugins/data/public'; import { Vis, VisParams } from '../types'; +import { VisAugmenterEmbeddableConfig, VisLayers } from '../../../../plugins/vis_augmenter/public'; + const { isDateHistogramBucketAggConfig } = search.aggs; interface SchemaConfigParams { @@ -85,6 +87,8 @@ export interface BuildPipelineParams { timefilter: TimefilterContract; timeRange?: any; abortSignal?: AbortSignal; + visLayers?: VisLayers; + visAugmenterConfig?: VisAugmenterEmbeddableConfig; } const vislibCharts: string[] = [ @@ -331,7 +335,20 @@ const buildVisConfig: BuildVisConfigFunction = { }, }; -export const buildVislibDimensions = async (vis: any, params: BuildPipelineParams) => { +export interface VislibDimensions { + x: any; + y: SchemaConfig[]; + z?: any[]; + width?: any[]; + series?: any[]; + splitRow?: any[]; + splitColumn?: any[]; +} + +export const buildVislibDimensions = async ( + vis: any, + params: BuildPipelineParams +): Promise => { const schemas = getSchemas(vis, { timeRange: params.timeRange, timefilter: params.timefilter, diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts index 682e678ed584..3542e0cc26ff 100644 --- a/src/plugins/visualizations/public/plugin.ts +++ b/src/plugins/visualizations/public/plugin.ts @@ -37,6 +37,7 @@ import { Plugin, ApplicationStart, SavedObjectsClientContract, + NotificationsStart, } from '../../../core/public'; import { TypesService, TypesSetup, TypesStart } from './vis_types'; import { @@ -54,12 +55,14 @@ import { setExpressions, setUiActions, setSavedVisualizationsLoader, + setSavedAugmentVisLoader, setTimeFilter, setAggs, setChrome, setOverlays, setSavedSearchLoader, setEmbeddable, + setNotifications, } from './services'; import { VISUALIZE_EMBEDDABLE_TYPE, @@ -92,6 +95,7 @@ import { } from './saved_visualizations/_saved_vis'; import { createSavedSearchesLoader } from '../../discover/public'; import { DashboardStart } from '../../dashboard/public'; +import { createSavedAugmentVisLoader } from '../../vis_augmenter/public'; /** * Interface for this plugin's returned setup/start contracts. @@ -128,6 +132,7 @@ export interface VisualizationsStartDeps { dashboard: DashboardStart; getAttributeService: DashboardStart['getAttributeService']; savedObjectsClient: SavedObjectsClientContract; + notifications: NotificationsStart; } /** @@ -177,6 +182,14 @@ export class VisualizationsPlugin { data, expressions, uiActions, embeddable, dashboard }: VisualizationsStartDeps ): VisualizationsStart { const types = this.types.start(); + const savedAugmentVisLoader = createSavedAugmentVisLoader({ + savedObjectsClient: core.savedObjects.client, + indexPatterns: data.indexPatterns, + search: data.search, + chrome: core.chrome, + overlays: core.overlays, + }); + setSavedAugmentVisLoader(savedAugmentVisLoader); setI18n(core.i18n); setTypes(types); setEmbeddable(embeddable); @@ -210,6 +223,7 @@ export class VisualizationsPlugin overlays: core.overlays, }); setSavedSearchLoader(savedSearchLoader); + setNotifications(core.notifications); return { ...types, showNewVisModal, diff --git a/src/plugins/visualizations/public/services.ts b/src/plugins/visualizations/public/services.ts index e3f3ba56f6b1..a99a7010af28 100644 --- a/src/plugins/visualizations/public/services.ts +++ b/src/plugins/visualizations/public/services.ts @@ -37,6 +37,7 @@ import { IUiSettingsClient, OverlayStart, SavedObjectsStart, + NotificationsStart, } from '../../../core/public'; import { TypesStart } from './vis_types'; import { createGetterSetter } from '../../opensearch_dashboards_utils/common'; @@ -52,6 +53,7 @@ import { UiActionsStart } from '../../ui_actions/public'; import { SavedVisualizationsLoader } from './saved_visualizations'; import { SavedObjectLoader } from '../../saved_objects/public'; import { EmbeddableStart } from '../../embeddable/public'; +import { SavedObjectLoaderAugmentVis } from '../../vis_augmenter/public'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); @@ -106,3 +108,11 @@ export const [getChrome, setChrome] = createGetterSetter('Chrome'); export const [getSavedSearchLoader, setSavedSearchLoader] = createGetterSetter( 'savedSearchLoader' ); + +export const [getNotifications, setNotifications] = createGetterSetter( + 'Notifications' +); + +export const [getSavedAugmentVisLoader, setSavedAugmentVisLoader] = createGetterSetter< + SavedObjectLoaderAugmentVis +>('savedAugmentVisLoader'); diff --git a/src/plugins/visualizations/server/plugin.ts b/src/plugins/visualizations/server/plugin.ts index 1be4eaa65050..3c1453fe750c 100644 --- a/src/plugins/visualizations/server/plugin.ts +++ b/src/plugins/visualizations/server/plugin.ts @@ -83,10 +83,13 @@ export class VisualizationsPlugin defaultMessage: 'Disable visualizations bucket aggregation types', }), value: [], - description: i18n.translate('visualizations.advancedSettings.visualizeDisableBucketAgg', { - defaultMessage: `A comma-separated list of bucket aggregations' names. e.g. significant_terms, terms. + description: i18n.translate( + 'visualizations.advancedSettings.visualizeDisableBucketAgg.description', + { + defaultMessage: `A comma-separated list of bucket aggregations' names. e.g. significant_terms, terms. Deactivates the specified bucket aggregations from visualizations.`, - }), + } + ), category: ['visualization'], schema: schema.arrayOf(schema.string()), }, diff --git a/src/plugins/visualize/opensearch_dashboards.json b/src/plugins/visualize/opensearch_dashboards.json index c898f7da3779..47573b58b9d2 100644 --- a/src/plugins/visualize/opensearch_dashboards.json +++ b/src/plugins/visualize/opensearch_dashboards.json @@ -19,6 +19,7 @@ "opensearchDashboardsReact", "home", "discover", - "visDefaultEditor" + "visDefaultEditor", + "savedObjectsManagement" ] } diff --git a/src/plugins/visualize/public/application/components/visualize_listing.tsx b/src/plugins/visualize/public/application/components/visualize_listing.tsx index 46db44bb066d..5dab2f11051c 100644 --- a/src/plugins/visualize/public/application/components/visualize_listing.tsx +++ b/src/plugins/visualize/public/application/components/visualize_listing.tsx @@ -29,7 +29,6 @@ */ import './visualize_listing.scss'; - import React, { useCallback, useRef, useMemo, useEffect } from 'react'; import { i18n } from '@osd/i18n'; import { useUnmount, useMount } from 'react-use'; @@ -43,6 +42,8 @@ import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../../visualizations/public import { VisualizeServices } from '../types'; import { VisualizeConstants } from '../visualize_constants'; import { getTableColumns, getNoItemsMessage } from '../utils'; +import { getUiActions } from '../../services'; +import { SAVED_OBJECT_DELETE_TRIGGER } from '../../../../saved_objects_management/public'; export const VisualizeListing = () => { const { @@ -134,15 +135,29 @@ export const VisualizeListing = () => { const deleteItems = useCallback( async (selectedItems: object[]) => { + const uiActions = getUiActions(); await Promise.all( - selectedItems.map((item: any) => savedObjects.client.delete(item.savedObjectType, item.id)) - ).catch((error) => { - toastNotifications.addError(error, { - title: i18n.translate('visualize.visualizeListingDeleteErrorTitle', { - defaultMessage: 'Error deleting visualization', - }), - }); - }); + selectedItems.map((item: any) => + savedObjects.client + .delete(item.savedObjectType, item.id) + .then(() => { + /** + * TODO: this should be automatically handled by the saved objects plugin. Tracking issue: + * https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4499 + */ + uiActions + .getTrigger(SAVED_OBJECT_DELETE_TRIGGER) + .exec({ type: item.savedObjectType, savedObjectId: item.id }); + }) + .catch((error) => { + toastNotifications.addError(error, { + title: i18n.translate('visualize.visualizeListingDeleteErrorTitle', { + defaultMessage: 'Error deleting visualization', + }), + }); + }) + ) + ); }, [savedObjects.client, toastNotifications] ); diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 297db26c48de..c146efef1fab 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -60,13 +60,14 @@ import { DEFAULT_APP_CATEGORIES } from '../../../core/public'; import { SavedObjectsStart } from '../../saved_objects/public'; import { EmbeddableStart } from '../../embeddable/public'; import { DashboardStart } from '../../dashboard/public'; -import { UiActionsSetup, VISUALIZE_FIELD_TRIGGER } from '../../ui_actions/public'; +import { UiActionsSetup, UiActionsStart, VISUALIZE_FIELD_TRIGGER } from '../../ui_actions/public'; import { setUISettings, setApplication, setIndexPatterns, setQueryService, setShareService, + setUiActions, } from './services'; import { visualizeFieldAction } from './actions/visualize_field_action'; import { createVisualizeUrlGenerator } from './url_generator'; @@ -80,6 +81,7 @@ export interface VisualizePluginStartDependencies { urlForwarding: UrlForwardingStart; savedObjects: SavedObjectsStart; dashboard: DashboardStart; + uiActions: UiActionsStart; } export interface VisualizePluginSetupDependencies { @@ -248,6 +250,7 @@ export class VisualizePlugin if (plugins.share) { setShareService(plugins.share); } + setUiActions(plugins.uiActions); } stop() { diff --git a/src/plugins/visualize/public/services.ts b/src/plugins/visualize/public/services.ts index c0f359e8a002..ac367522ab7e 100644 --- a/src/plugins/visualize/public/services.ts +++ b/src/plugins/visualize/public/services.ts @@ -32,6 +32,7 @@ import { ApplicationStart, IUiSettingsClient } from '../../../core/public'; import { createGetterSetter } from '../../../plugins/opensearch_dashboards_utils/public'; import { IndexPatternsContract, DataPublicPluginStart } from '../../../plugins/data/public'; import { SharePluginStart } from '../../share/public'; +import { UiActionsStart } from '../../ui_actions/public'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); @@ -46,3 +47,5 @@ export const [getIndexPatterns, setIndexPatterns] = createGetterSetter('Query'); + +export const [getUiActions, setUiActions] = createGetterSetter('UIActions'); diff --git a/test/common/services/opensearch_archiver.ts b/test/common/services/opensearch_archiver.ts index 3985c7aaf466..b422ef69068f 100644 --- a/test/common/services/opensearch_archiver.ts +++ b/test/common/services/opensearch_archiver.ts @@ -39,7 +39,7 @@ export function OpenSearchArchiverProvider({ hasService, }: FtrProviderContext): OpenSearchArchiver { const config = getService('config'); - const client = getService('legacyOpenSearch'); + const client = getService('opensearch'); const log = getService('log'); if (!config.get('opensearchArchiver')) { diff --git a/test/functional/apps/dashboard/dashboard_state.js b/test/functional/apps/dashboard/dashboard_state.js index d4ca87821204..5beca47f9cae 100644 --- a/test/functional/apps/dashboard/dashboard_state.js +++ b/test/functional/apps/dashboard/dashboard_state.js @@ -75,14 +75,14 @@ export default function ({ getService, getPageObjects }) { await PageObjects.dashboard.switchToEditMode(); await PageObjects.visChart.openLegendOptionColors('Count'); - await PageObjects.visChart.selectNewLegendColorChoice('#EA6460'); + await PageObjects.visChart.selectNewLegendColorChoice('#8d4059'); await PageObjects.dashboard.saveDashboard('Overridden colors'); await PageObjects.dashboard.gotoDashboardLandingPage(); await PageObjects.dashboard.loadSavedDashboard('Overridden colors'); const colorChoiceRetained = await PageObjects.visChart.doesSelectedLegendColorExist( - '#EA6460' + '#8d4059' ); expect(colorChoiceRetained).to.be(true); @@ -153,7 +153,9 @@ export default function ({ getService, getPageObjects }) { expect(headers.length).to.be(0); }); - it('Tile map with no changes will update with visualization changes', async () => { + // TODO: race condition it seems with the query from previous state + // https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4193 + it.skip('Tile map with no changes will update with visualization changes', async () => { await PageObjects.dashboard.gotoDashboardLandingPage(); await PageObjects.dashboard.clickNewDashboard(); @@ -243,9 +245,9 @@ export default function ({ getService, getPageObjects }) { it('updates a pie slice color on a soft refresh', async function () { await dashboardAddPanel.addVisualization(PIE_CHART_VIS_NAME); await PageObjects.visChart.openLegendOptionColors('80,000'); - await PageObjects.visChart.selectNewLegendColorChoice('#F9D9F9'); + await PageObjects.visChart.selectNewLegendColorChoice('#e9b0c3'); const currentUrl = await browser.getCurrentUrl(); - const newUrl = currentUrl.replace('F9D9F9', 'FFFFFF'); + const newUrl = currentUrl.replace('e9b0c3', 'FFFFFF'); await browser.get(newUrl.toString(), false); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -277,14 +279,14 @@ export default function ({ getService, getPageObjects }) { await retry.try(async () => { const pieSliceStyle = await pieChart.getPieSliceStyle('80,000'); - // The default green color that was stored with the visualization before any dashboard overrides. - expect(pieSliceStyle.indexOf('rgb(87, 193, 123)')).to.be.greaterThan(0); + // The default color that was stored with the visualization before any dashboard overrides. + expect(pieSliceStyle.indexOf('rgb(84, 179, 153)')).to.be.greaterThan(0); }); }); it('resets the legend color as well', async function () { await retry.try(async () => { - const colorExists = await PageObjects.visChart.doesSelectedLegendColorExist('#57c17b'); + const colorExists = await PageObjects.visChart.doesSelectedLegendColorExist('#54B399'); expect(colorExists).to.be(true); }); }); diff --git a/test/functional/apps/visualize/_area_chart.js b/test/functional/apps/visualize/_area_chart.js index 86fdb1879b7e..3ca202501667 100644 --- a/test/functional/apps/visualize/_area_chart.js +++ b/test/functional/apps/visualize/_area_chart.js @@ -521,13 +521,15 @@ export default function ({ getService, getPageObjects }) { it('should show error when calendar interval invalid', async () => { await PageObjects.visEditor.setInterval('14d', { type: 'custom' }); - const intervalErrorMessage = await find.byCssSelector( - '[data-test-subj="visEditorInterval"] + .euiFormErrorText' - ); + const intervalErrorMessageSelector = + '[data-test-subj="visEditorInterval"] + .euiFormErrorText'; + + let intervalErrorMessage = await find.byCssSelector(intervalErrorMessageSelector); let errorMessage = await intervalErrorMessage.getVisibleText(); expect(errorMessage).to.be('Invalid calendar interval: 2w, value must be 1'); await PageObjects.visEditor.setInterval('3w', { type: 'custom' }); + intervalErrorMessage = await find.byCssSelector(intervalErrorMessageSelector); errorMessage = await intervalErrorMessage.getVisibleText(); expect(errorMessage).to.be('Invalid calendar interval: 3w, value must be 1'); }); diff --git a/test/functional/page_objects/header_page.ts b/test/functional/page_objects/header_page.ts index aa05dd12d8dc..f9a873c49ced 100644 --- a/test/functional/page_objects/header_page.ts +++ b/test/functional/page_objects/header_page.ts @@ -73,7 +73,7 @@ export function HeaderPageProvider({ getService, getPageObjects }: FtrProviderCo } public async clickStackManagement() { - await appsMenu.clickLink('Stack Management', { category: 'management' }); + await appsMenu.clickLink('Dashboards Management', { category: 'management' }); await this.awaitGlobalLoadingIndicatorHidden(); } diff --git a/test/functional/page_objects/visualize_chart_page.ts b/test/functional/page_objects/visualize_chart_page.ts index e13d8eed6081..975da7cc552a 100644 --- a/test/functional/page_objects/visualize_chart_page.ts +++ b/test/functional/page_objects/visualize_chart_page.ts @@ -286,7 +286,7 @@ export function VisualizeChartPageProvider({ getService, getPageObjects }: FtrPr await testSubjects.click(`legend-${name}`); await this.waitForVisualizationRenderingStabilized(); // arbitrary color chosen, any available would do - const isOpen = await this.doesLegendColorChoiceExist('#EF843C'); + const isOpen = await this.doesLegendColorChoiceExist('#e09e64'); if (!isOpen) { throw new Error('legend color selector not open'); } diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index 8e1f9fd07a1c..3cd2fb250bf6 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -188,9 +188,12 @@ export function ComboBoxProvider({ getService, getPageObjects }: FtrProviderCont log.debug(`comboBox.getOptionsList, comboBoxSelector: ${comboBoxSelector}`); const comboBox = await testSubjects.find(comboBoxSelector); const menu = await retry.try(async () => { - await testSubjects.click(comboBoxSelector); + let isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); + if (!isOptionsListOpen) { + await testSubjects.click('comboBoxToggleListButton', undefined, comboBoxSelector); + } await this.waitForOptionsListLoading(comboBox); - const isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); + isOptionsListOpen = await testSubjects.exists('~comboBoxOptionsList'); if (!isOptionsListOpen) { throw new Error('Combo box options list did not open on click'); } diff --git a/test/functional/services/common/find.ts b/test/functional/services/common/find.ts index ee28fa02cc52..c80401ed0517 100644 --- a/test/functional/services/common/find.ts +++ b/test/functional/services/common/find.ts @@ -435,11 +435,19 @@ export async function FindProvider({ getService }: FtrProviderContext) { public async clickByCssSelector( selector: string, - timeout: number = defaultFindTimeout + timeout: number = defaultFindTimeout, + parentSelector?: string ): Promise { log.debug(`Find.clickByCssSelector('${selector}') with timeout=${timeout}`); await retry.try(async () => { - const element = await this.byCssSelector(selector, timeout); + let element; + if (parentSelector) { + const parent = await this.byCssSelector(parentSelector, timeout); + const child = await parent._webElement.findElement(By.css(selector)); + element = wrap(child, By.css(selector)); + } else { + element = await this.byCssSelector(selector, timeout); + } if (element) { // await element.moveMouseTo(); await element.click(); diff --git a/test/functional/services/common/test_subjects.ts b/test/functional/services/common/test_subjects.ts index 2c96b61c66da..242a37151500 100644 --- a/test/functional/services/common/test_subjects.ts +++ b/test/functional/services/common/test_subjects.ts @@ -122,9 +122,17 @@ export function TestSubjectsProvider({ getService }: FtrProviderContext) { await find.clickByCssSelectorWhenNotDisabled(testSubjSelector(selector), { timeout }); } - public async click(selector: string, timeout: number = FIND_TIME): Promise { + public async click( + selector: string, + timeout: number = FIND_TIME, + parentSelector?: string + ): Promise { log.debug(`TestSubjects.click(${selector})`); - await find.clickByCssSelector(testSubjSelector(selector), timeout); + await find.clickByCssSelector( + testSubjSelector(selector), + timeout, + parentSelector && testSubjSelector(parentSelector) + ); } public async doubleClick(selector: string, timeout: number = FIND_TIME): Promise { 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 5f308268566c..326ca8753a76 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.1.1", + "@elastic/eui": "npm:@opensearch-project/oui@1.3.0-alpha.2", "@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 35f7e84ae0e2..16579e3f07e6 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.1.1", + "@elastic/eui": "npm:@opensearch-project/oui@1.3.0-alpha.2", "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 13f7b1695a0d..b74231619c98 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.1.1", + "@elastic/eui": "npm:@opensearch-project/oui@1.3.0-alpha.2", "@osd/plugin-helpers": "1.0.0", "react": "^16.14.0", "typescript": "4.0.2" diff --git a/tsconfig.browser.json b/tsconfig.browser.json index b0886bf3e5e2..7ec0041c8fbf 100644 --- a/tsconfig.browser.json +++ b/tsconfig.browser.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "target": "es5", + "target": "es2018", "module": "esnext", }, "include": [ diff --git a/typings/index.d.ts b/typings/index.d.ts index 17a1b2139e34..ef7cf0239229 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -46,6 +46,12 @@ declare module '*.svg' { export default content; } +declare module '*.txt' { + const content: string; + // eslint-disable-next-line import/no-default-export + export default content; +} + type MethodKeysOf = { [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never; }[keyof T]; diff --git a/yarn.lock b/yarn.lock index e1985b3cd645..2f420f4e0d96 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1273,10 +1273,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.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@opensearch-project/oui/-/oui-1.1.1.tgz#4a9318c2954659cdd8d83263ff2dc22a77cbd779" - integrity sha512-RBXbsZh6mjJKJqB/hSI2loenyM2rvdq9id29P/ZYlZGKKy0/tSreIOGcegSYMtNFmG029D20xVkhRmdn7cxK1A== +"@elastic/eui@npm:@opensearch-project/oui@1.3.0-alpha.2": + version "1.3.0-alpha.2" + resolved "https://registry.yarnpkg.com/@opensearch-project/oui/-/oui-1.3.0-alpha.2.tgz#90060e68ba9809239b7ee22a4f12c65e94e80028" + integrity sha512-RZ+23jgnz2vYgfipd++gNT9zsSNbqm8XEyE9vr6jMMGiwL/XCUJ/7Vli5Z3BpQb1XPQVklRQscMoG2UT9xEpxQ== dependencies: "@types/chroma-js" "^2.0.0" "@types/lodash" "^4.14.160" @@ -2899,6 +2899,13 @@ resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.36.tgz#00d9301d4dc35c2f6465a8aec634bb533674c652" integrity sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q== +"@types/browserslist@^4.15.0": + version "4.15.0" + resolved "https://registry.yarnpkg.com/@types/browserslist/-/browserslist-4.15.0.tgz#ba0265b33003a2581df1fc5f483321a30205f2d2" + integrity sha512-h9LyKErRGZqMsHh9bd+FE8yCIal4S0DxKTOeui56VgVXqa66TKiuaIUxCAI7c1O0LjaUzOTcsMyOpO9GetozRA== + dependencies: + browserslist "*" + "@types/cacheable-request@^6.0.1": version "6.0.2" resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9" @@ -2967,21 +2974,6 @@ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== -"@types/cp-file@*": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@types/cp-file/-/cp-file-6.1.2.tgz#3c579201715ca6177d34f3e14f2b29861c470c4c" - integrity sha512-wvqCNhHt+GMfEglZ83cQ+8dEv5Oh8DwEq6IBBBL7+hWISR+82l/bSmssCo5zGHg7HpW6+kjZwDby9zGkCStN5w== - dependencies: - cp-file "*" - -"@types/cpy@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/cpy/-/cpy-5.1.0.tgz#ced20cbae8528031ae5478f1d0fe4bca2518eda7" - integrity sha512-NU7IrYOZx+K2YCo7muReOj6FIxEWdWXCN7hgRhQ+h2lgpeLy27si9ZzdDwWCW+Q1RP9B1lDTJ368FPFSOp1ZqA== - dependencies: - "@types/cp-file" "*" - "@types/glob" "*" - "@types/d3@^3.5.43": version "3.5.47" resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.47.tgz#b81042fcb0195c583fc037bc857d161469a7d175" @@ -3686,10 +3678,10 @@ resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.9.tgz#12621e55b2ef8f6c98bd17fe23fa720c6cba16bd" integrity sha512-HopIwBE7GUXsscmt/J0DhnFXLSmO04AfxT6b8HAprknwka7pqEWquWDMXxCjd+NUHK9MkCe1SDKKsMiNmCItbQ== -"@types/semver@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" - integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ== +"@types/semver@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== "@types/sinon@^7.0.13": version "7.5.2" @@ -4866,12 +4858,12 @@ autobind-decorator@^1.3.4: integrity sha1-TJb/p3sQYi7eJPEQ9du/VmkUF9E= autoprefixer@^10.4.1: - version "10.4.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" - integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== + version "10.4.14" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" + integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== dependencies: - browserslist "^4.20.2" - caniuse-lite "^1.0.30001317" + browserslist "^4.21.5" + caniuse-lite "^1.0.30001464" fraction.js "^4.2.0" normalize-range "^0.1.2" picocolors "^1.0.0" @@ -5345,16 +5337,25 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.17.5, browserslist@^4.19.1, browserslist@^4.20.2: - version "4.20.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" - integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== +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.30001317" - electron-to-chromium "^1.4.84" - escalade "^3.1.1" - node-releases "^2.0.2" - picocolors "^1.0.0" + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +browserslist@^4.17.5, browserslist@^4.19.1, 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" bser@2.1.1: version "2.1.1" @@ -5596,10 +5597,15 @@ 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.30001317: - version "1.0.30001460" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz" - integrity sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ== +caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503: + version "1.0.30001517" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz#90fabae294215c3495807eb24fc809e11dc2f0a8" + integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA== + +caniuse-lite@^1.0.30001517: + version "1.0.30001519" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601" + integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg== ccount@^1.0.0: version "1.1.0" @@ -6115,6 +6121,13 @@ commander@^5.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +comment-stripper@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/comment-stripper/-/comment-stripper-0.0.4.tgz#e8d61366d362779ea225c764f05cca6c950f8a2c" + integrity sha512-4K87KyAmZtZmAUznIJuVsBB7v328V4GBL2wVhno71aunUymMfYBVaAWITH4jrH6uI7NbxpczSdl7NysHx+XfYg== + dependencies: + loader-utils "^2.0.0" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -6303,16 +6316,6 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" -cp-file@*: - version "9.1.0" - resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-9.1.0.tgz#e98e30db72d57d47b5b1d444deb70d05e5684921" - integrity sha512-3scnzFj/94eb7y4wyXRWwvzLFaQp87yyfTnChIjlfYrVqp5lVO3E2hIJMeQIltUT0K2ZAB3An1qXcBmwGyvuwA== - dependencies: - graceful-fs "^4.1.2" - make-dir "^3.0.0" - nested-error-stacks "^2.0.0" - p-event "^4.1.0" - cp-file@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" @@ -7473,10 +7476,15 @@ elasticsearch@^16.4.0, elasticsearch@^16.7.0: chalk "^1.0.0" lodash "^4.17.10" -electron-to-chromium@^1.4.84: - version "1.4.102" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.102.tgz#fec312f753bcd9b89396136147efdb8bbd55cc82" - integrity sha512-MuWg3/gLTk6PSjC7ZrTgT8aAYZmUYd+gRtD95vN77KMBwZXiGdHHa8Y7ppMc/zwNumZtoIBLS0rzZyjEHd7sNw== +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== elegant-spinner@^1.0.1: version "1.0.1" @@ -13184,15 +13192,15 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" -node-releases@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" - integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== +node-releases@^2.0.12, 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== -node-sass@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-8.0.0.tgz#c80d52148db0ce88610bcf1e1d112027393c13e1" - integrity sha512-jPzqCF2/e6JXw6r3VxfIqYc8tKQdkj5Z/BDATYyG6FL6b/LuYBNFGFVhus0mthcWifHm/JzBpKAd+3eXsWeK/A== +"node-sass@npm:@amoo-miki/node-sass@9.0.0-libsass-3.6.5": + version "9.0.0-libsass-3.6.5" + resolved "https://registry.yarnpkg.com/@amoo-miki/node-sass/-/node-sass-9.0.0-libsass-3.6.5.tgz#0536f4890b2a7a9143ce536f0fecde0a02ee389b" + integrity sha512-KalEkSO9qBbenHS1fXwz6UAf3x2oUKguJ6DRbTyDn8lYiZqNrEcbaD3hE8eZiLOrH662n8MF7fVzLp+oMQNiEA== dependencies: async-foreach "^0.1.3" chalk "^4.1.2" @@ -15587,16 +15595,16 @@ sass-graph@^4.0.1: scss-tokenizer "^0.4.3" yargs "^17.2.1" -sass-loader@^10.4.1: - version "10.4.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.4.1.tgz#bea4e173ddf512c9d7f53e9ec686186146807cbf" - integrity sha512-aX/iJZTTpNUNx/OSYzo2KsjIUQHqvWsAhhUijFjAPdZTEhstjZI9zTNvkTTwsx+uNUJqUwOw5gacxQMx4hJxGQ== +"sass-loader@npm:@amoo-miki/sass-loader@10.4.1-node-sass-9.0.0-libsass-3.6.5": + version "10.4.1-node-sass-9.0.0-libsass-3.6.5" + resolved "https://registry.yarnpkg.com/@amoo-miki/sass-loader/-/sass-loader-10.4.1-node-sass-9.0.0-libsass-3.6.5.tgz#d1cb70a9a708d29bbe94522c1bd7e945406f3a14" + integrity sha512-jZhlf9wVKR3xk8rmOHjBbC0Wur7ly3iDNv+usZ7ioPE/SBUAeoUu89VQKswxD6bhjcvlnFf8AmkeqztCn6oNMg== dependencies: klona "^2.0.4" loader-utils "^2.0.0" neo-async "^2.6.2" schema-utils "^3.0.0" - semver "^7.3.2" + semver "^7.5.4" sax@1.2.1: version "1.2.1" @@ -15677,30 +15685,10 @@ selenium-webdriver@^4.0.0-alpha.7: rimraf "^2.7.1" tmp "0.0.30" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - -semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.8, semver@~7.3.0: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== +"semver@2 || 3 || 4 || 5", semver@7.0.0, semver@7.3.2, semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~7.3.0: + version "7.5.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" + integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== dependencies: lru-cache "^6.0.0" @@ -17194,14 +17182,15 @@ topojson-client@^3.1.0: dependencies: commander "2" -tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== +tough-cookie@^4.0.0, tough-cookie@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== dependencies: psl "^1.1.33" punycode "^2.1.1" - universalify "^0.1.2" + universalify "^0.2.0" + url-parse "^1.5.3" tr46@^1.0.1: version "1.0.1" @@ -17673,11 +17662,16 @@ unist-util-visit@^2.0.0, unist-util-visit@^2.0.3: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" -universalify@^0.1.0, universalify@^0.1.2: +universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + unlazy-loader@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/unlazy-loader/-/unlazy-loader-0.1.3.tgz#2efdf05c489da311055586bf3cfca0c541dd8fa5" @@ -17698,6 +17692,14 @@ 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" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -17719,7 +17721,7 @@ url-loader@^2.2.0: mime "^2.4.4" schema-utils "^2.5.0" -url-parse@^1.5.9: +url-parse@^1.5.3, url-parse@^1.5.9: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== @@ -18630,9 +18632,9 @@ wildcard@^2.0.0: integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + version "1.2.4" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" + integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== wordwrap@^1.0.0: version "1.0.0"