diff --git a/.babelrc b/.babelrc index dbb4d9ccb..5abc3e8e5 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,4 @@ { "presets": ["@babel/preset-env", "@babel/preset-react","@babel/preset-typescript"], - "plugins": ["@babel/plugin-transform-runtime"] + "plugins": ["@babel/plugin-transform-runtime", "istanbul"] } diff --git a/.github/workflows/develop-deployment.yml b/.github/workflows/develop-deployment.yml index 100d29938..75018ea40 100644 --- a/.github/workflows/develop-deployment.yml +++ b/.github/workflows/develop-deployment.yml @@ -1,57 +1,57 @@ name: Test/Deploy Develop on: - push: - branches: [ develop ] + push: + branches: [develop] jobs: - build-test: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: Creating Neo4j Container - run: | - chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh - ./scripts/docker-neo4j-initializer/docker-neo4j.sh - sleep 30s - chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh - ./scripts/docker-neo4j-initializer/start-movies-db.sh - - run: rm -rf docs - - run: yarn install - - name: Eslint check - run: yarn run lint - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - build: yarn run build - start: yarn run dev - wait-on: 'http://localhost:3000' - build-s3: - needs: build-test - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - run: yarn install - - run: yarn run build-minimal - - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-west-1 - - run: curl ${{ secrets.INDEX_HTML_DEPLOYMENT_URL }} > dist/index.html - - run: aws s3 rm s3://neodash-test.graphapp.io/ --recursive && aws s3 sync dist s3://neodash-test.graphapp.io/ --acl public-read + build-test: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Creating Neo4j Container + run: | + chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh + ./scripts/docker-neo4j-initializer/docker-neo4j.sh + sleep 30s + chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh + ./scripts/docker-neo4j-initializer/start-movies-db.sh + - run: yarn install + - name: Eslint check + run: yarn run lint + - name: Cypress run + uses: cypress-io/github-action@v4 + with: + build: yarn run build + start: yarn run dev + wait-on: "http://localhost:3000" + browser: chrome + build-s3: + needs: build-test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: yarn install + - run: yarn run build-minimal + - name: Set AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-1 + - run: curl ${{ secrets.INDEX_HTML_DEPLOYMENT_URL }} > dist/index.html + - run: aws s3 rm s3://neodash-test.graphapp.io/ --recursive && aws s3 sync dist s3://neodash-test.graphapp.io/ --acl public-read diff --git a/.github/workflows/develop-test.yml b/.github/workflows/develop-test.yml index 1f6ca4bc0..f65fe9ca0 100644 --- a/.github/workflows/develop-test.yml +++ b/.github/workflows/develop-test.yml @@ -1,34 +1,37 @@ name: Test Develop on: - pull_request: - branches: [ develop ] + pull_request: + branches: [develop] jobs: - build-test: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: Creating Neo4j Container - run: | - chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh - ./scripts/docker-neo4j-initializer/docker-neo4j.sh - sleep 30s - chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh - ./scripts/docker-neo4j-initializer/start-movies-db.sh - - run: yarn install - - name: Eslint check - run: yarn run lint - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - build: yarn run build - start: yarn run dev - wait-on: 'http://localhost:3000' + build-test: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Creating Neo4j Container + run: | + chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh + ./scripts/docker-neo4j-initializer/docker-neo4j.sh + sleep 30s + chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh + ./scripts/docker-neo4j-initializer/start-movies-db.sh + - run: yarn install + - name: Eslint check + run: yarn run lint + - name: Cypress run + uses: cypress-io/github-action@v4 + with: + build: yarn run build + start: yarn run dev + wait-on: 'http://localhost:3000' + browser: chrome + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/master-deployment.yml b/.github/workflows/master-deployment.yml index 861d80483..2a58a661e 100644 --- a/.github/workflows/master-deployment.yml +++ b/.github/workflows/master-deployment.yml @@ -1,167 +1,130 @@ name: Test/Deploy Master on: - push: - branches: [ master ] + push: + branches: [master] jobs: - build-test: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: Creating Neo4j Container - run: | - chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh - ./scripts/docker-neo4j-initializer/docker-neo4j.sh - sleep 30s - chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh - ./scripts/docker-neo4j-initializer/start-movies-db.sh - - run: rm -rf docs - - run: yarn install - - name: Eslint check - run: yarn run lint - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - build: yarn run build - start: yarn run dev - wait-on: 'http://localhost:3000' -# build-s3: -# needs: build-test -# runs-on: ubuntu-latest -# strategy: -# matrix: -# node-version: [18.x] -# steps: -# - uses: actions/checkout@v2 -# - name: Use Node.js ${{ matrix.node-version }} -# uses: actions/setup-node@v1 -# with: -# node-version: ${{ matrix.node-version }} -# - run: rm -rf docs -# - run: yarn install -# - run: yarn run build-minimal -# - name: Set AWS credentials -# uses: aws-actions/configure-aws-credentials@v1 -# with: -# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} -# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} -# aws-region: us-west-1 -# - run: curl ${{ secrets.INDEX_HTML_DEPLOYMENT_URL }} > dist/index.html -# - run: aws s3 rm s3://neodash.graphapp.io/ --recursive && aws s3 sync dist s3://neodash.graphapp.io/ --acl public-read - build-docker: - needs: build-test - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - name: run Docker - uses: actions/checkout@v2 - - run: rm -rf docs - - name: Login to Docker Hub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_LABS_USERNAME }} - password: ${{ secrets.DOCKER_HUB_LABS_ACCESS_TOKEN }} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - file: ./Dockerfile - push: true - tags: ${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_LABS_USERNAME }}/neodash:2.2.5 - build-docker-legacy: - needs: build-test - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - name: run Docker - uses: actions/checkout@v2 - - run: rm -rf docs - - name: Login to Docker Hub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_USERNAME }} - password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - file: ./Dockerfile - push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.2.5 -# build-npm: -# needs: build-test -# runs-on: ubuntu-latest -# strategy: -# matrix: -# node-version: [18.x] -# steps: -# - uses: actions/checkout@v2 -# - name: Use Node.js ${{ matrix.node-version }} -# uses: actions/setup-node@v1 -# with: -# node-version: ${{ matrix.node-version }} -# - run: rm -rf docs -# - run: yarn install-minimal -# - run: yarn run build-minimal -# - run: curl ${{ secrets.INDEX_HTML_DEPLOYMENT_URL }} > dist/index.html -# - run: npm pack -# - run: rm -rf target -# - run: mkdir target -# - run: mv *.tgz target/ -# - run: tar -xvf target/*.tgz -# - run: rm -f target/*.tgz -# - run: cp package/dist/favicon.ico package/favicon.ico -# - run: echo "${{ secrets.NEO4J_LABS_APP_KEY }}" > neo4j-labs-app.pem -# - run: echo "${{ secrets.NEO4J_LABS_APP_CERTIFICATE }}" > neo4j-labs-app.cert -# - run: npx @neo4j/code-signer --app ./package --private-key neo4j-labs-app.pem --cert neo4j-labs-app.cert --passphrase ${{ secrets.NEO4J_DESKTOP_PASSPHRASE }} -# - run: echo "${{ secrets.NEO4J_DESKTOP_CERTIFICATE }}" > neo4j_desktop.cert -# - run: npx @neo4j/code-signer --verify --app ./package --root-cert neo4j_desktop.cert -# - run: cd package && npm pack -# - run: mv package/*.tgz . -# - run: rm -rf package -# - run: tar xvf *.tgz package -# - run: npx @neo4j/code-signer --verify --app ./package --root-cert neo4j_desktop.cert -# - run: rm -rf package -# - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc -# - name: Publish package to NPM 📦 -# run: npm publish --access public neodash*.tgz - deploy-gallery: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - run: cd gallery && yarn install - - run: cd gallery && yarn run build - - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-west-1 - - run: aws s3 rm s3://neodash-gallery.graphapp.io/ --recursive && aws s3 sync gallery/build s3://neodash-gallery.graphapp.io/ --acl public-read - deploy-docs: + build-test: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Creating Neo4j Container + run: | + chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh + ./scripts/docker-neo4j-initializer/docker-neo4j.sh + sleep 30s + chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh + ./scripts/docker-neo4j-initializer/start-movies-db.sh + - run: yarn install + - name: Eslint check + run: yarn run lint + - name: Cypress run + uses: cypress-io/github-action@v4 + with: + build: yarn run build + start: yarn run dev + wait-on: "http://localhost:3000" + browser: chrome + build-s3: + needs: build-test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: rm -rf docs + - run: yarn install + - run: yarn run build-minimal + - name: Set AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-1 + - run: curl ${{ secrets.INDEX_HTML_DEPLOYMENT_URL }} > dist/index.html + - run: aws s3 rm s3://neodash.graphapp.io/ --recursive && aws s3 sync dist s3://neodash.graphapp.io/ --acl public-read + build-docker: + needs: build-test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - name: run Docker + uses: actions/checkout@v2 + - run: rm -rf docs + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + - name: Set up Docker Build + uses: docker/setup-buildx-action@v1 + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.3.0 + build-docker-legacy: + needs: build-test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - name: run Docker + uses: actions/checkout@v2 + - run: rm -rf docs + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/neodash:latest,${{ secrets.DOCKER_HUB_USERNAME }}/neodash:2.3.0 + deploy-gallery: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: cd gallery && yarn install + - run: cd gallery && yarn run build + - name: Set AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-1 + - run: aws s3 rm s3://neodash-gallery.graphapp.io/ --recursive && aws s3 sync gallery/build s3://neodash-gallery.graphapp.io/ --acl public-read + deploy-docs: needs: build-test runs-on: ubuntu-latest steps: @@ -170,4 +133,41 @@ jobs: with: token: ${{ secrets.DOCS_REFRESH_TOKEN }} repository: neo4j-documentation/docs-refresh - event-type: labs \ No newline at end of file + event-type: labs + build-npm: + needs: build-test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: rm -rf docs + - run: yarn install + - run: PRODUCTION=true && yarn run build-minimal + - run: curl ${{ secrets.INDEX_HTML_DEPLOYMENT_URL }} > dist/index.html + - run: npm pack + - run: rm -rf target + - run: mkdir target + - run: mv *.tgz target/ + - run: tar -xvf target/*.tgz + - run: rm -f target/*.tgz + - run: cp package/dist/favicon.ico package/favicon.ico + - run: echo "${{ secrets.NEO4J_LABS_APP_KEY }}" > neo4j-labs-app.pem + - run: echo "${{ secrets.NEO4J_LABS_APP_CERTIFICATE }}" > neo4j-labs-app.cert + - run: npx @neo4j/code-signer --app ./package --private-key neo4j-labs-app.pem --cert neo4j-labs-app.cert --passphrase ${{ secrets.NEO4J_DESKTOP_PASSPHRASE }} + - run: echo "${{ secrets.NEO4J_DESKTOP_CERTIFICATE }}" > neo4j_desktop.cert + - run: npx @neo4j/code-signer --verify --app ./package --root-cert neo4j_desktop.cert + - run: cd package && npm pack + - run: mv package/*.tgz . + - run: rm -rf package + - run: tar xvf *.tgz package + - run: npx @neo4j/code-signer --verify --app ./package --root-cert neo4j_desktop.cert + - run: rm -rf package + - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc + - name: Publish package to NPM 📦 + run: npm publish --access public neodash*.tgz diff --git a/.github/workflows/master-test.yml b/.github/workflows/master-test.yml index f1873f402..e17690c41 100644 --- a/.github/workflows/master-test.yml +++ b/.github/workflows/master-test.yml @@ -1,34 +1,35 @@ name: Test Master on: - pull_request: - branches: [ master ] + pull_request: + branches: [master] jobs: - build-test: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: Creating Neo4j Container - run: | - chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh - ./scripts/docker-neo4j-initializer/docker-neo4j.sh - sleep 30s - chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh - ./scripts/docker-neo4j-initializer/start-movies-db.sh - - run: yarn install - - name: Eslint check - run: yarn run lint - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - build: yarn run build - start: yarn run dev - wait-on: 'http://localhost:3000' + build-test: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Creating Neo4j Container + run: | + chmod +x ./scripts/docker-neo4j-initializer/docker-neo4j.sh + ./scripts/docker-neo4j-initializer/docker-neo4j.sh + sleep 30s + chmod +x ./scripts/docker-neo4j-initializer/start-movies-db.sh + ./scripts/docker-neo4j-initializer/start-movies-db.sh + - run: yarn install + - name: Eslint check + run: yarn run lint + - name: Cypress run + uses: cypress-io/github-action@v4 + with: + build: yarn run build + start: yarn run dev + wait-on: "http://localhost:3000" + browser: chrome diff --git a/.gitignore b/.gitignore index 20471195f..4f24f1de4 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,7 @@ target # testing /coverage -cypress/plugins -cypress/support +/.nyc_output cypress/videos # production diff --git a/Dockerfile b/Dockerfile index e6f969cba..c443d4fd3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,15 +18,18 @@ RUN yarn run build-minimal # production stage FROM nginx:alpine AS neodash RUN apk upgrade -COPY --from=build-stage /usr/local/src/neodash/dist /usr/share/nginx/html -COPY ./conf/default.conf /etc/nginx/conf.d/ +ENV NGINX_PORT=5005 + +COPY --from=build-stage /usr/local/src/neodash/dist /usr/share/nginx/html +COPY ./conf/default.conf.template /etc/nginx/templates/ COPY ./scripts/config-entrypoint.sh /docker-entrypoint.d/config-entrypoint.sh COPY ./scripts/message-entrypoint.sh /docker-entrypoint.d/message-entrypoint.sh RUN chown -R nginx:nginx /var/cache/nginx && \ chown -R nginx:nginx /var/log/nginx && \ chown -R nginx:nginx /etc/nginx/conf.d && \ + chown -R nginx:nginx /etc/nginx/templates && \ chown -R nginx:nginx /docker-entrypoint.d/config-entrypoint.sh && \ chmod +x /docker-entrypoint.d/config-entrypoint.sh && \ chmod +x /docker-entrypoint.d/message-entrypoint.sh @@ -36,6 +39,8 @@ RUN chown -R nginx:nginx /usr/share/nginx/html/ ## Launch webserver as non-root user. USER nginx -EXPOSE 5005 -HEALTHCHECK cmd curl --fail http://localhost:5005 || exit 1 -LABEL version="2.2.5" + +EXPOSE $NGINX_PORT + +HEALTHCHECK cmd curl --fail "http://localhost:$NGINX_PORT" || exit 1 +LABEL version="2.3.0" diff --git a/LICENSE b/LICENSE index fc2d75a74..ddee50d37 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2022 Niels de Jong + Copyright 2023 Niels de Jong Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index f468be47d..414f5185e 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ To manually run linting of all your .ts and .tsx staged files, run: yarn run lint-staged ``` -See the [Developer Guide](https://neo4j.com/labs/neodash/2.2/developer-guide/) for more on installing, building, and running the application. +See the [Developer Guide](https://neo4j.com/labs/neodash/2.3/developer-guide/) for more on installing, building, and running the application. ### Pre-Commit Hook While commiting, a pre-commit hook will be executed in order to prettify and run the Linter on your staged files. Linter warnings are currently accepted. The commands executed by this hook can be found in /.lintstagedrc.json. @@ -67,10 +67,10 @@ There is also a dedicated linting step in the Github project pipeline in order t ## User Guide NeoDash comes with built-in examples of dashboards and reports. For more details on the types of reports and how to customize them, see the [User Guide]( -https://neo4j.com/labs/neodash/2.2/user-guide/). +https://neo4j.com/labs/neodash/2.3/user-guide/). ## Publish Dashboards -After building a dashboard, you can chose to deploy a read-only, standalone instance for users. See [Publishing](https://neo4j.com/labs/neodash/2.2/user-guide/publishing/) for more on publishing dashboards. +After building a dashboard, you can chose to deploy a read-only, standalone instance for users. See [Publishing](https://neo4j.com/labs/neodash/2.3/user-guide/publishing/) for more on publishing dashboards. ## Questions / Suggestions diff --git a/changelog.md b/changelog.md index 41be6f190..89691e4a2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,37 @@ +## NeoDash 2.3.0 +NeoDash 2.3 is out! This release brings a brand new look-and-feel, improved speed for large dashboards, and a new extension for querying Neo4j with natural language (using LLMs). + +Key features: +- Write **[Natural Language Queries](https://neo4j.com/labs/neodash/2.3/user-guide/extensions/natural-language-queries/)** and use OpenAI to generate Cypher queries for your visualizations. +- UI updated to use the **[Neo4j Design Language](https://www.neo4j.design/)**, giving NeoDash a similar look-and-feel to other Neo4j tools. +- Customize branding, colors dynamically with a new [Style Configuration File](https://neo4j.com/labs/neodash/2.3/developer-guide/style-configuration). + +Other changes: +- Fixed issues with date picker / free-text parameter sometimes not initializing. +- Improved documentation by fixing broken links, and adding more details around complex concepts. +- **Pro Extensions have evolved to open Expert Extensions.** +- Fixed issue where deep-linked parameters were not set from the URL. +- Added option to specify absolute width for table columns (in pixels or as percentages). +- Fixed map charts to auto-cluster markers when they collide, or are too close together. +- ... and dozens of other improvements! + + + +Contributors to this release: +- [Alfredo Rubin](https://github.com/alfredorubin96) +- [Harold Agudelo](https://github.com/BennuFire) +- [Aleksandar Simeunovic](https://github.com/AleSim94) +- [Marius Conjeaud](https://github.com/mariusconjeaud) +- [Brahm Prakash Mishra](https://github.com/brahmprakashMishra) +- [Pierre Martignon](https://github.com/pierremartignon) +- [Kim Zachariassen](https://github.com/KiZach) +- [Paolo Baldini](https://github.com/8Rav3n) +- [Niels de Jong](https://github.com/nielsdejong/) + + ## NeoDash 2.2.5 This is a minor release with some small bug fixes, directly following the 2.2.4 release. -- Fixed replacement rules for parameters in iFrames/Markdown reports. [#17](https://github.com/neo4j-labs/neodash/pull/417) +- Fixed replacement rules for parameters in iFrames/Markdown reports. [#417](https://github.com/neo4j-labs/neodash/pull/417) - Added automatic header text color switch for reports with a dark background [#420](https://github.com/neo4j-labs/neodash/pull/420) - Fixed handling right click events (for graph exploration) in Neo4j Desktop [#415](https://github.com/neo4j-labs/neodash/pull/415). - Added support for unweighted Sankey charts [#419](https://github.com/neo4j-labs/neodash/pull/419) @@ -102,7 +133,7 @@ This release marks the official arrival of **[Extensions](https://neo4j.com/labs NeoDash 2.2 comes with three in-built extensions. - **Rule-Based Styling** - **Advanced Visualizations**: These provide a means to enable complex visualizations in a dashboard. These were previously available as Radar charts, Treemaps, Circle Packing reports, Sankey charts, Choropleth and a Gauge Chart). -- **Report Actions**: Which let you create interactivity in dashboards, using the output of one report as input for another visualization. (Pro Extension) +- **Report Actions**: Which let you create interactivity in dashboards, using the output of one report as input for another visualization. (Expert Extension) You can enable extensions by clicking the 🧩 icon on the left sidebar of the screen. diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 000000000..a56e13883 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,9 @@ +services: + neodash: + build: + context: . + dockerfile: Dockerfile + ports: + - "5005:5005" + environment: + - NGINX_PORT=5005 diff --git a/conf/default.conf b/conf/default.conf.template similarity index 93% rename from conf/default.conf rename to conf/default.conf.template index 7c404c2dd..c65835a2f 100644 --- a/conf/default.conf +++ b/conf/default.conf.template @@ -1,5 +1,5 @@ server { - listen 5005; + listen ${NGINX_PORT}; server_name localhost; include mime.types; location / { diff --git a/cypress.config.ts b/cypress.config.ts new file mode 100644 index 000000000..dbcd424d0 --- /dev/null +++ b/cypress.config.ts @@ -0,0 +1,18 @@ +/* eslint @typescript-eslint/no-var-requires: "off" */ +import { defineConfig } from 'cypress'; + +export default defineConfig({ + projectId: 'a8nh14', + video: false, + e2e: { + baseUrl: 'http://localhost:3000', + setupNodeEvents(on, config) { + return require('./cypress/plugins/index.js')(on, config); + }, + }, + env: { + codeCoverage: { + exclude: ['cypress/**/*.*'], + }, + }, +}); diff --git a/cypress.json b/cypress.json deleted file mode 100644 index b2550c86f..000000000 --- a/cypress.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "baseUrl": "http://localhost:3000", - "video": false -} \ No newline at end of file diff --git a/cypress/integration/start_page.spec.js b/cypress/e2e/start_page.cy.js similarity index 58% rename from cypress/integration/start_page.spec.js rename to cypress/e2e/start_page.cy.js index 3759ec4aa..6ea9f0f46 100644 --- a/cypress/integration/start_page.spec.js +++ b/cypress/e2e/start_page.cy.js @@ -10,6 +10,7 @@ import { gaugeChartCypherQuery, } from '../fixtures/cypher_queries'; +const WAITING_TIME = 20000; // Ignore warnings that may appear when using the Cypress dev server Cypress.on('uncaught:exception', (err, runnable) => { console.log(err, runnable); @@ -18,22 +19,25 @@ Cypress.on('uncaught:exception', (err, runnable) => { describe('NeoDash E2E Tests', () => { beforeEach(() => { - cy.clearLocalStorage(); cy.viewport(1920, 1080); // Navigate to index - cy.visit('/'); - cy.wait(1000); + cy.visit('/', { + onBeforeLoad(win) { + win.localStorage.clear(); + }, + }); + + cy.get('#form-dialog-title', { timeout: 2000 }).should('be.visible'); cy.get('#form-dialog-title').then(($div) => { const text = $div.text(); - if (text == 'NeoDash - Neo4j Dashboard Builder⚡') { - cy.wait(300); + if (text == 'NeoDash - Neo4j Dashboard Builder') { + cy.wait(500); // Create new dashboard cy.contains('New Dashboard').click(); } }); - cy.wait(300); // If an old dashboard exists in cache, do a check to make sure we clear it. // if (cy.contains("Create new dashboard")) { // cy.contains('Yes').click() @@ -45,35 +49,41 @@ describe('NeoDash E2E Tests', () => { // cy.get('#protocol').click() // cy.contains('neo4j').click() cy.get('#url').clear().type('localhost'); - cy.wait(100); // cy.get('#database').type('neo4j') cy.get('#dbusername').clear().type('neo4j'); - cy.get('#dbpassword').type('test'); - cy.wait(100); + cy.get('#dbpassword').type('test1234'); cy.get('button').contains('Connect').click(); cy.wait(100); }); it('initializes the dashboard', () => { - // Check the starter cards - cy.get('main .react-grid-item:eq(0)').should('contain', 'This is your first dashboard!'); - cy.get('main .react-grid-item:eq(1) .force-graph-container canvas').should('be.visible'); - cy.get('main .react-grid-item:eq(2) button').should('have.attr', 'aria-label', 'add'); + checkInitialState(); }); it('creates a new card', () => { - cy.get('main .react-grid-item:eq(2) button').click(); - cy.get('main .react-grid-item:eq(2)').should('contain', 'No query specified.'); + checkInitialState(); + createCard(); }); // Test each type of card it('creates a table report', () => { - cy.get('main .react-grid-item:eq(2) button').click(); - cy.get('main .react-grid-item:eq(2) button[aria-label="settings"]').click(); - cy.get('main .react-grid-item:eq(2) .MuiInputLabel-root').contains('Type').next().should('contain', 'Table'); + checkInitialState(); + cy.get('main .react-grid-item button[aria-label="add report"]').should('be.visible').click(); + cy.get('main .react-grid-item') + .contains('No query specified.') + .parentsUntil('.react-grid-item') + .find('button[aria-label="settings"]', { timeout: 2000 }) + .should('be.visible') + .click(); + + cy.get('main .react-grid-item:eq(2) #type input[name="Type"]').should('have.value', 'Table'); cy.get('main .react-grid-item:eq(2) .ReactCodeMirror').type(tableCypherQuery); - cy.get('main .react-grid-item:eq(2) button[aria-label="save"]').click(); - cy.get('main .react-grid-item:eq(2) .MuiDataGrid-columnHeaders') + cy.wait(400); + + cy.get('main .react-grid-item:eq(2)').contains('Advanced settings').click(); + + cy.get('main .react-grid-item:eq(2) button[aria-label="run"]').click(); + cy.get('main .react-grid-item:eq(2) .MuiDataGrid-columnHeaders', { timeout: WAITING_TIME }) .should('contain', 'title') .and('contain', 'released') .and('not.contain', '__id'); @@ -85,42 +95,36 @@ describe('NeoDash E2E Tests', () => { }); it('creates a bar chart report', () => { + checkInitialState(); createReportOfType('Bar Chart', barChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Category') - .next() - .should('contain', 'released'); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Value') - .next() - .should('contain', 'count'); + cy.get('main .react-grid-item:eq(2) #index input[name="Category"]', { timeout: WAITING_TIME }).should( + 'have.value', + 'released' + ); + cy.get('main .react-grid-item:eq(2) #value input[name="Value"]').should('have.value', 'count'); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > g').should('have.length', 8); }); it('creates a pie chart report', () => { + checkInitialState(); createReportOfType('Pie Chart', barChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Category') - .next() - .should('contain', 'released'); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Value') - .next() - .should('contain', 'count'); + cy.get('main .react-grid-item:eq(2) #index input[name="Category"]', { timeout: WAITING_TIME }).should( + 'have.value', + 'released' + ); + cy.get('main .react-grid-item:eq(2) #value input[name="Value"]').should('have.value', 'count'); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > g').should('have.length', 3); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > g:nth-child(2) > path').should('have.length', 5); }); it('creates a line chart report', () => { + checkInitialState(); createReportOfType('Line Chart', barChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('X-value') - .next() - .should('contain', 'released'); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Y-value') - .next() - .should('contain', 'count'); + cy.get('main .react-grid-item:eq(2) #x input[name="X-value"]', { timeout: WAITING_TIME }).should( + 'have.value', + 'released' + ); + cy.get('main .react-grid-item:eq(2) #value input[name="Y-value"]').should('have.value', 'count'); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > g').should('have.length', 6); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > g:nth-child(2) > line').should( 'have.length', @@ -129,105 +133,115 @@ describe('NeoDash E2E Tests', () => { }); it('creates a map chart report', () => { - createReportOfType('Map', mapChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > path').should('have.length', 5); + checkInitialState(); + createReportOfType('Map', mapChartCypherQuery, true); + cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > path', { timeout: WAITING_TIME }).should( + 'have.length', + 5 + ); }); it('creates a single value report', () => { + checkInitialState(); createReportOfType('Single Value', barChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardContent-root > div > div:nth-child(2) > span') + cy.get('main .react-grid-item:eq(2) .MuiCardContent-root > div > div:nth-child(2) > span', { + timeout: WAITING_TIME, + }) .invoke('text') .then((text) => { - expect(text).to.be.oneOf(['1999', '1,999']); + expect(text).to.be.oneOf(['1999', '1,999', '1 999']); }); }); it('creates a gauge chart report', () => { enableAdvancedVisualizations(); + checkInitialState(); createReportOfType('Gauge Chart', gaugeChartCypherQuery); - cy.get('.text-group > text').contains('69'); + cy.get('.text-group > text', { timeout: WAITING_TIME }).contains('69'); }); it('creates a sunburst chart report', () => { enableAdvancedVisualizations(); + checkInitialState(); createReportOfType('Sunburst Chart', sunburstChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Path') - .next() - .should('contain', 'x.path'); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Value') - .next() - .should('contain', 'x.value'); + cy.get('main .react-grid-item:eq(2) #index input[name="Path"]', { timeout: WAITING_TIME }).should( + 'have.value', + 'x.path' + ); + cy.get('main .react-grid-item:eq(2) #value input[name="Value"]').should('have.value', 'x.value'); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > g:nth-child(1) > path').should('have.length', 5); }); it('creates a circle packing report', () => { enableAdvancedVisualizations(); + checkInitialState(); createReportOfType('Circle Packing', sunburstChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Path') - .next() - .should('contain', 'x.path'); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Value') - .next() - .should('contain', 'x.value'); + cy.get('main .react-grid-item:eq(2) #index input[name="Path"]', { timeout: WAITING_TIME }).should( + 'have.value', + 'x.path' + ); + cy.get('main .react-grid-item:eq(2) #value input[name="Value"]').should('have.value', 'x.value'); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > circle').should('have.length', 6); }); it('creates a tree map report', () => { enableAdvancedVisualizations(); + checkInitialState(); createReportOfType('Treemap', sunburstChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Path') - .next() - .should('contain', 'x.path'); - cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root') - .contains('Value') - .next() - .should('contain', 'x.value'); + cy.get('main .react-grid-item:eq(2) #index input[name="Path"]', { timeout: WAITING_TIME }).should( + 'have.value', + 'x.path' + ); + cy.get('main .react-grid-item:eq(2) #value input[name="Value"]').should('have.value', 'x.value'); cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > g').should('have.length', 6); }); it('creates a sankey chart report', () => { enableAdvancedVisualizations(); + checkInitialState(); createReportOfType('Sankey Chart', sankeyChartCypherQuery, true); - cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > path').should('have.attr', 'fill-opacity', 0.5); + cy.get('main .react-grid-item:eq(2) .MuiCardContent-root svg > g > path', { timeout: WAITING_TIME }).should( + 'have.attr', + 'fill-opacity', + 0.5 + ); }); it('creates a raw json report', () => { + checkInitialState(); createReportOfType('Raw JSON', barChartCypherQuery); - cy.get('main .react-grid-item:eq(2) .MuiCardContent-root textarea:nth-child(1)').should(($div) => { - const text = $div.text(); - expect(text.length).to.eq(1387); - }); + cy.get('main .react-grid-item:eq(2) .MuiCardContent-root textarea:nth-child(1)', { timeout: 45000 }).should( + ($div) => { + const text = $div.text(); + expect(text.length).to.eq(1387); + } + ); }); it('creates a parameter select report', () => { - cy.get('main .react-grid-item:eq(2) button').click(); - cy.get('main .react-grid-item:eq(2) button[aria-label="settings"]').click(); - cy.get('main .react-grid-item:eq(2) .MuiInputLabel-root').contains('Type').next().click(); - cy.contains('Parameter Select').click(); - cy.wait(300); + checkInitialState(); + selectReportOfType('Parameter Select'); + cy.wait(500); cy.get('#autocomplete-label-type').type('Movie'); cy.get('#autocomplete-label-type-option-0').click(); - cy.wait(300); + cy.wait(500); cy.get('#autocomplete-property').type('title'); cy.get('#autocomplete-property-option-0').click(); - cy.get('main .react-grid-item:eq(2) button[aria-label="save"]').click(); + cy.get('main .react-grid-item:eq(2) button[aria-label="run"]').click(); cy.get('#autocomplete').type('The Matrix'); cy.get('#autocomplete-option-0').click(); }); it('creates an iframe report', () => { + checkInitialState(); createReportOfType('iFrame', iFrameText); - cy.get('main .react-grid-item:eq(2) .MuiCardContent-root iframe'); + cy.get('main .react-grid-item:eq(2) .MuiCardContent-root iframe', { timeout: 45000 }).should('be.visible'); }); it('creates a markdown report', () => { + checkInitialState(); createReportOfType('Markdown', markdownText); - cy.get('main .react-grid-item:eq(2) .MuiCardContent-root h1').should('have.text', 'Hello'); + cy.get('main .react-grid-item:eq(2) .MuiCardContent-root h1', { timeout: 45000 }).should('have.text', 'Hello'); }); // it('creates a radar report', () => { @@ -265,24 +279,48 @@ describe('NeoDash E2E Tests', () => { }); function enableAdvancedVisualizations() { - cy.get('#extensions-sidebar-button').click(); - cy.wait(100); - cy.get('#checkbox-advanced-charts').click(); - cy.wait(100); - cy.get('#extensions-modal-close-button').click(); + cy.get('#extensions-sidebar-button').should('be.visible').click(); + cy.get('#checkbox-advanced-charts').should('be.visible').click(); + cy.get('.ndl-dialog-close').scrollIntoView().should('be.visible').click(); cy.wait(200); } -function createReportOfType(type, query, fast = false) { - cy.get('main .react-grid-item:eq(2) button').click(); - cy.get('main .react-grid-item:eq(2) button[aria-label="settings"]').click(); - cy.get('main .react-grid-item:eq(2) .MuiInputLabel-root').contains('Type').next().click(); +function selectReportOfType(type) { + cy.get('main .react-grid-item button[aria-label="add report"]').should('be.visible').click(); + cy.get('main .react-grid-item') + .contains('No query specified.') + .parentsUntil('.react-grid-item') + .find('button[aria-label="settings"]', { timeout: 2000 }) + .should('be.visible') + .click(); + cy.get('main .react-grid-item:eq(2) #type', { timeout: 2000 }).should('be.visible').click(); cy.contains(type).click(); + cy.wait(100); +} + +function createReportOfType(type, query, fast = false) { + selectReportOfType(type); if (fast) { cy.get('main .react-grid-item:eq(2) .ReactCodeMirror').type(query, { delay: 1, parseSpecialCharSequences: false }); } else { cy.get('main .react-grid-item:eq(2) .ReactCodeMirror').type(query, { parseSpecialCharSequences: false }); } + cy.wait(400); + + cy.get('main .react-grid-item:eq(2)').contains('Advanced settings').click(); + + cy.get('main .react-grid-item:eq(2) button[aria-label="run"]').click(); +} + +function checkInitialState() { + // Check the starter cards + cy.get('main .react-grid-item:eq(0)').should('contain', 'This is your first dashboard!'); + cy.get('main .react-grid-item:eq(1) .force-graph-container canvas').should('be.visible'); + cy.get('main .react-grid-item:eq(2) button').should('have.attr', 'aria-label', 'add report'); +} - cy.get('main .react-grid-item:eq(2) button[aria-label="save"]').click(); +function createCard() { + // Check the starter cards + cy.get('main .react-grid-item:eq(2) button[aria-label="add report"]').click(); + cy.get('main .react-grid-item:eq(2)').should('contain', 'No query specified.'); } diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 000000000..cd82581e8 --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,6 @@ +module.exports = (on, config) => { + require('@cypress/code-coverage/task')(on, config); + //Used to instrument code ran like unit tests + on('file:preprocessor', require('@cypress/code-coverage/use-babelrc')); + return config; +}; diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 000000000..119ab03f7 --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts new file mode 100644 index 000000000..c3401c0a3 --- /dev/null +++ b/cypress/support/e2e.ts @@ -0,0 +1,22 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands'; + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +import '@cypress/code-coverage/support'; diff --git a/docs/README.md b/docs/README.md index 2054a448e..1a1f09e4f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,7 +6,7 @@ An external workflow picks up this directory, embeds it into the Neo4j docs, and ``` https://neo4j.com/labs/neodash/{version} ``` -For example: https://neo4j.com/labs/neodash/2.2 +For example: https://neo4j.com/labs/neodash/2.3 ## Local Build To compile and view the documentation locally, navigate to this (`./docs`) folder and run: diff --git a/docs/antora.yml b/docs/antora.yml index d06c4b663..34fdc5c69 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: neodash -version: 2.2 +version: 2.3 title: NeoDash start_page: ROOT:index.adoc nav: @@ -7,7 +7,7 @@ nav: asciidoc: attributes: - docs-version: 2.2 + docs-version: 2.3 page-product: NeoDash page-type: NeoDash Manual page-canonical-root: /labs \ No newline at end of file diff --git a/docs/modules/ROOT/images/about.png b/docs/modules/ROOT/images/about.png index 5efc14e6c..c72648a2f 100644 Binary files a/docs/modules/ROOT/images/about.png and b/docs/modules/ROOT/images/about.png differ diff --git a/docs/modules/ROOT/images/advanced-visualizations.png b/docs/modules/ROOT/images/advanced-visualizations.png index 09fe04a0f..aaf904710 100644 Binary files a/docs/modules/ROOT/images/advanced-visualizations.png and b/docs/modules/ROOT/images/advanced-visualizations.png differ diff --git a/docs/modules/ROOT/images/areamap-countries.png b/docs/modules/ROOT/images/areamap-countries.png index 945ec763b..8202489af 100644 Binary files a/docs/modules/ROOT/images/areamap-countries.png and b/docs/modules/ROOT/images/areamap-countries.png differ diff --git a/docs/modules/ROOT/images/areamap-regions.png b/docs/modules/ROOT/images/areamap-regions.png index 19647f7b1..6bafe29a7 100644 Binary files a/docs/modules/ROOT/images/areamap-regions.png and b/docs/modules/ROOT/images/areamap-regions.png differ diff --git a/docs/modules/ROOT/images/bar.png b/docs/modules/ROOT/images/bar.png index 5cd6173ee..7bc2bd441 100644 Binary files a/docs/modules/ROOT/images/bar.png and b/docs/modules/ROOT/images/bar.png differ diff --git a/docs/modules/ROOT/images/barstacked.png b/docs/modules/ROOT/images/barstacked.png index 8b16b05d0..8032e5826 100644 Binary files a/docs/modules/ROOT/images/barstacked.png and b/docs/modules/ROOT/images/barstacked.png differ diff --git a/docs/modules/ROOT/images/choropleth.png b/docs/modules/ROOT/images/choropleth.png index 41503532b..2c359ef47 100644 Binary files a/docs/modules/ROOT/images/choropleth.png and b/docs/modules/ROOT/images/choropleth.png differ diff --git a/docs/modules/ROOT/images/circlepacking.png b/docs/modules/ROOT/images/circlepacking.png index c851fdc29..195cd7bf4 100644 Binary files a/docs/modules/ROOT/images/circlepacking.png and b/docs/modules/ROOT/images/circlepacking.png differ diff --git a/docs/modules/ROOT/images/component-hierarchy.png b/docs/modules/ROOT/images/component-hierarchy.png index 715001169..c6272cf32 100644 Binary files a/docs/modules/ROOT/images/component-hierarchy.png and b/docs/modules/ROOT/images/component-hierarchy.png differ diff --git a/docs/modules/ROOT/images/cypress.png b/docs/modules/ROOT/images/cypress.png index 4cecf5fbd..6d4007aea 100644 Binary files a/docs/modules/ROOT/images/cypress.png and b/docs/modules/ROOT/images/cypress.png differ diff --git a/docs/modules/ROOT/images/dashboard.png b/docs/modules/ROOT/images/dashboard.png index 0ee4fe28d..91f7f912e 100644 Binary files a/docs/modules/ROOT/images/dashboard.png and b/docs/modules/ROOT/images/dashboard.png differ diff --git a/docs/modules/ROOT/images/dashboard2.png b/docs/modules/ROOT/images/dashboard2.png index 3dfca5005..028258ff0 100644 Binary files a/docs/modules/ROOT/images/dashboard2.png and b/docs/modules/ROOT/images/dashboard2.png differ diff --git a/docs/modules/ROOT/images/dashboardsettings.png b/docs/modules/ROOT/images/dashboardsettings.png index 6c2fb90cc..33f2e8619 100644 Binary files a/docs/modules/ROOT/images/dashboardsettings.png and b/docs/modules/ROOT/images/dashboardsettings.png differ diff --git a/docs/modules/ROOT/images/englisheditor.png b/docs/modules/ROOT/images/englisheditor.png new file mode 100644 index 000000000..54206d2d5 Binary files /dev/null and b/docs/modules/ROOT/images/englisheditor.png differ diff --git a/docs/modules/ROOT/images/extensionbutton.png b/docs/modules/ROOT/images/extensionbutton.png new file mode 100644 index 000000000..a6c45bd32 Binary files /dev/null and b/docs/modules/ROOT/images/extensionbutton.png differ diff --git a/docs/modules/ROOT/images/extensions.png b/docs/modules/ROOT/images/extensions.png index 180376c06..a628389cc 100644 Binary files a/docs/modules/ROOT/images/extensions.png and b/docs/modules/ROOT/images/extensions.png differ diff --git a/docs/modules/ROOT/images/gauge.png b/docs/modules/ROOT/images/gauge.png index dc832e8d6..25fabd24a 100644 Binary files a/docs/modules/ROOT/images/gauge.png and b/docs/modules/ROOT/images/gauge.png differ diff --git a/docs/modules/ROOT/images/graph.png b/docs/modules/ROOT/images/graph.png index 4eac01c05..6b63db78b 100644 Binary files a/docs/modules/ROOT/images/graph.png and b/docs/modules/ROOT/images/graph.png differ diff --git a/docs/modules/ROOT/images/graph2.png b/docs/modules/ROOT/images/graph2.png index 424013adb..07f582b69 100644 Binary files a/docs/modules/ROOT/images/graph2.png and b/docs/modules/ROOT/images/graph2.png differ diff --git a/docs/modules/ROOT/images/graphdrilldown.png b/docs/modules/ROOT/images/graphdrilldown.png index 7d9cb55e9..232d67341 100644 Binary files a/docs/modules/ROOT/images/graphdrilldown.png and b/docs/modules/ROOT/images/graphdrilldown.png differ diff --git a/docs/modules/ROOT/images/graphexploration.png b/docs/modules/ROOT/images/graphexploration.png new file mode 100644 index 000000000..091bb06e0 Binary files /dev/null and b/docs/modules/ROOT/images/graphexploration.png differ diff --git a/docs/modules/ROOT/images/iframe.png b/docs/modules/ROOT/images/iframe.png index 6230099f3..d6666ce56 100644 Binary files a/docs/modules/ROOT/images/iframe.png and b/docs/modules/ROOT/images/iframe.png differ diff --git a/docs/modules/ROOT/images/iframe2.png b/docs/modules/ROOT/images/iframe2.png index c82983ce1..e10cf9e07 100644 Binary files a/docs/modules/ROOT/images/iframe2.png and b/docs/modules/ROOT/images/iframe2.png differ diff --git a/docs/modules/ROOT/images/json.png b/docs/modules/ROOT/images/json.png index 5a9febd16..9af8e175f 100644 Binary files a/docs/modules/ROOT/images/json.png and b/docs/modules/ROOT/images/json.png differ diff --git a/docs/modules/ROOT/images/line1.png b/docs/modules/ROOT/images/line1.png index 039d210ce..84622c4f4 100644 Binary files a/docs/modules/ROOT/images/line1.png and b/docs/modules/ROOT/images/line1.png differ diff --git a/docs/modules/ROOT/images/line2.png b/docs/modules/ROOT/images/line2.png index f96feaddd..4a4c02666 100644 Binary files a/docs/modules/ROOT/images/line2.png and b/docs/modules/ROOT/images/line2.png differ diff --git a/docs/modules/ROOT/images/llmconfiguration.png b/docs/modules/ROOT/images/llmconfiguration.png new file mode 100644 index 000000000..f3d64bbad Binary files /dev/null and b/docs/modules/ROOT/images/llmconfiguration.png differ diff --git a/docs/modules/ROOT/images/map.png b/docs/modules/ROOT/images/map.png index e63496329..ee9199799 100644 Binary files a/docs/modules/ROOT/images/map.png and b/docs/modules/ROOT/images/map.png differ diff --git a/docs/modules/ROOT/images/map2.png b/docs/modules/ROOT/images/map2.png index f1b5deb53..0d37f91d1 100644 Binary files a/docs/modules/ROOT/images/map2.png and b/docs/modules/ROOT/images/map2.png differ diff --git a/docs/modules/ROOT/images/map3.png b/docs/modules/ROOT/images/map3.png index 08d445595..ded3dd760 100644 Binary files a/docs/modules/ROOT/images/map3.png and b/docs/modules/ROOT/images/map3.png differ diff --git a/docs/modules/ROOT/images/map_cluster.png b/docs/modules/ROOT/images/map_cluster.png index f17ddd160..8bc7fb5a5 100644 Binary files a/docs/modules/ROOT/images/map_cluster.png and b/docs/modules/ROOT/images/map_cluster.png differ diff --git a/docs/modules/ROOT/images/map_heatmap.png b/docs/modules/ROOT/images/map_heatmap.png index 652890ec7..52b1def24 100644 Binary files a/docs/modules/ROOT/images/map_heatmap.png and b/docs/modules/ROOT/images/map_heatmap.png differ diff --git a/docs/modules/ROOT/images/markdown.png b/docs/modules/ROOT/images/markdown.png index 6892344d3..d24d27f87 100644 Binary files a/docs/modules/ROOT/images/markdown.png and b/docs/modules/ROOT/images/markdown.png differ diff --git a/docs/modules/ROOT/images/movereport.gif b/docs/modules/ROOT/images/movereport.gif index 2ef8e57d2..db2754077 100644 Binary files a/docs/modules/ROOT/images/movereport.gif and b/docs/modules/ROOT/images/movereport.gif differ diff --git a/docs/modules/ROOT/images/page.png b/docs/modules/ROOT/images/page.png index c8efef564..01e86f0c7 100644 Binary files a/docs/modules/ROOT/images/page.png and b/docs/modules/ROOT/images/page.png differ diff --git a/docs/modules/ROOT/images/pie.png b/docs/modules/ROOT/images/pie.png index 88fc12378..0908f5c00 100644 Binary files a/docs/modules/ROOT/images/pie.png and b/docs/modules/ROOT/images/pie.png differ diff --git a/docs/modules/ROOT/images/piedonut.png b/docs/modules/ROOT/images/piedonut.png index f70c93800..90c8fae64 100644 Binary files a/docs/modules/ROOT/images/piedonut.png and b/docs/modules/ROOT/images/piedonut.png differ diff --git a/docs/modules/ROOT/images/publish.png b/docs/modules/ROOT/images/publish.png index b55287544..a0486edd8 100644 Binary files a/docs/modules/ROOT/images/publish.png and b/docs/modules/ROOT/images/publish.png differ diff --git a/docs/modules/ROOT/images/radar.png b/docs/modules/ROOT/images/radar.png index 718a2fd98..1eff13467 100644 Binary files a/docs/modules/ROOT/images/radar.png and b/docs/modules/ROOT/images/radar.png differ diff --git a/docs/modules/ROOT/images/report-actions.png b/docs/modules/ROOT/images/report-actions.png index e30834fec..29f07e9a6 100644 Binary files a/docs/modules/ROOT/images/report-actions.png and b/docs/modules/ROOT/images/report-actions.png differ diff --git a/docs/modules/ROOT/images/report.gif b/docs/modules/ROOT/images/report.gif index e8a115139..7275fad49 100644 Binary files a/docs/modules/ROOT/images/report.gif and b/docs/modules/ROOT/images/report.gif differ diff --git a/docs/modules/ROOT/images/reportactions.png b/docs/modules/ROOT/images/reportactions.png index 1bf152bf6..cdf849744 100644 Binary files a/docs/modules/ROOT/images/reportactions.png and b/docs/modules/ROOT/images/reportactions.png differ diff --git a/docs/modules/ROOT/images/reportactionsbutton.png b/docs/modules/ROOT/images/reportactionsbutton.png index c6718e3fc..660600659 100644 Binary files a/docs/modules/ROOT/images/reportactionsbutton.png and b/docs/modules/ROOT/images/reportactionsbutton.png differ diff --git a/docs/modules/ROOT/images/resizereport.gif b/docs/modules/ROOT/images/resizereport.gif index 28aa60f7f..1ae835731 100644 Binary files a/docs/modules/ROOT/images/resizereport.gif and b/docs/modules/ROOT/images/resizereport.gif differ diff --git a/docs/modules/ROOT/images/rule-based-styling.png b/docs/modules/ROOT/images/rule-based-styling.png index d20419f6d..5e4c7c9bf 100644 Binary files a/docs/modules/ROOT/images/rule-based-styling.png and b/docs/modules/ROOT/images/rule-based-styling.png differ diff --git a/docs/modules/ROOT/images/rulebasedstyling.png b/docs/modules/ROOT/images/rulebasedstyling.png index ac7c2b985..3ab8f269c 100644 Binary files a/docs/modules/ROOT/images/rulebasedstyling.png and b/docs/modules/ROOT/images/rulebasedstyling.png differ diff --git a/docs/modules/ROOT/images/rulebasedstylingbutton.png b/docs/modules/ROOT/images/rulebasedstylingbutton.png index 7760633c1..b21f51eca 100644 Binary files a/docs/modules/ROOT/images/rulebasedstylingbutton.png and b/docs/modules/ROOT/images/rulebasedstylingbutton.png differ diff --git a/docs/modules/ROOT/images/sankey.png b/docs/modules/ROOT/images/sankey.png index c37d1666a..5c5d33a5c 100644 Binary files a/docs/modules/ROOT/images/sankey.png and b/docs/modules/ROOT/images/sankey.png differ diff --git a/docs/modules/ROOT/images/saveloadshare.png b/docs/modules/ROOT/images/saveloadshare.png index f1d9ae94e..20a63edfc 100644 Binary files a/docs/modules/ROOT/images/saveloadshare.png and b/docs/modules/ROOT/images/saveloadshare.png differ diff --git a/docs/modules/ROOT/images/select.png b/docs/modules/ROOT/images/select.png index 4058676d6..b866fb366 100644 Binary files a/docs/modules/ROOT/images/select.png and b/docs/modules/ROOT/images/select.png differ diff --git a/docs/modules/ROOT/images/select2.png b/docs/modules/ROOT/images/select2.png index c3fe467ea..7dbf800f4 100644 Binary files a/docs/modules/ROOT/images/select2.png and b/docs/modules/ROOT/images/select2.png differ diff --git a/docs/modules/ROOT/images/select3.png b/docs/modules/ROOT/images/select3.png index 0f7a7c427..7b8e10350 100644 Binary files a/docs/modules/ROOT/images/select3.png and b/docs/modules/ROOT/images/select3.png differ diff --git a/docs/modules/ROOT/images/select4.png b/docs/modules/ROOT/images/select4.png index 35a31b6e9..2920845b4 100644 Binary files a/docs/modules/ROOT/images/select4.png and b/docs/modules/ROOT/images/select4.png differ diff --git a/docs/modules/ROOT/images/select5.png b/docs/modules/ROOT/images/select5.png index a879c8210..1527ff575 100644 Binary files a/docs/modules/ROOT/images/select5.png and b/docs/modules/ROOT/images/select5.png differ diff --git a/docs/modules/ROOT/images/standalone-architecture.png b/docs/modules/ROOT/images/standalone-architecture.png index 39edc7d1d..ace1814f2 100644 Binary files a/docs/modules/ROOT/images/standalone-architecture.png and b/docs/modules/ROOT/images/standalone-architecture.png differ diff --git a/docs/modules/ROOT/images/sunburst.png b/docs/modules/ROOT/images/sunburst.png index 4c3411699..dcc9a824b 100644 Binary files a/docs/modules/ROOT/images/sunburst.png and b/docs/modules/ROOT/images/sunburst.png differ diff --git a/docs/modules/ROOT/images/table1.png b/docs/modules/ROOT/images/table1.png index 71bd1a67c..16cae32b6 100644 Binary files a/docs/modules/ROOT/images/table1.png and b/docs/modules/ROOT/images/table1.png differ diff --git a/docs/modules/ROOT/images/table2.png b/docs/modules/ROOT/images/table2.png index 1570aa010..8fbfe5f7f 100644 Binary files a/docs/modules/ROOT/images/table2.png and b/docs/modules/ROOT/images/table2.png differ diff --git a/docs/modules/ROOT/images/treemap.png b/docs/modules/ROOT/images/treemap.png index b90da188a..614427d1a 100644 Binary files a/docs/modules/ROOT/images/treemap.png and b/docs/modules/ROOT/images/treemap.png differ diff --git a/docs/modules/ROOT/images/value.png b/docs/modules/ROOT/images/value.png index 327e05051..4d8cc6aad 100644 Binary files a/docs/modules/ROOT/images/value.png and b/docs/modules/ROOT/images/value.png differ diff --git a/docs/modules/ROOT/images/value2.png b/docs/modules/ROOT/images/value2.png index 2935d8a93..bfeb22757 100644 Binary files a/docs/modules/ROOT/images/value2.png and b/docs/modules/ROOT/images/value2.png differ diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index c75d6f6a6..a9b0caa4c 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -29,6 +29,7 @@ *** xref:user-guide/extensions/advanced-visualizations.adoc[Advanced Visualizations] *** xref:user-guide/extensions/rule-based-styling.adoc[Rule-Based Styling] *** xref:user-guide/extensions/report-actions.adoc[Report Actions] +*** xref:user-guide/extensions/natural-language-queries.adoc[Natural Language Queries] ** xref:user-guide/faq.adoc[FAQ] * xref:developer-guide/index.adoc[Developer Guide] ** xref:developer-guide/build-and-run.adoc[Build & Run] @@ -39,6 +40,7 @@ ** xref:developer-guide/design.adoc[Design] ** xref:developer-guide/adding-visualizations.adoc[Adding Visualizations] ** xref:developer-guide/state-management.adoc[State Management] +** xref:developer-guide/session-storage.adoc[Session Storage] ** xref:developer-guide/testing.adoc[Testing] ** xref:developer-guide/contributing.adoc[Contributing] diff --git a/docs/modules/ROOT/pages/developer-guide/build-and-run.adoc b/docs/modules/ROOT/pages/developer-guide/build-and-run.adoc index f7e10bd31..45cbc2641 100644 --- a/docs/modules/ROOT/pages/developer-guide/build-and-run.adoc +++ b/docs/modules/ROOT/pages/developer-guide/build-and-run.adoc @@ -35,6 +35,10 @@ Pull the latest image from Docker Hub to run the application locally: # Run the application on http://localhost:5005 docker pull neo4jlabs/neodash:latest docker run -it --rm -p 5005:5005 neo4jlabs/neodash + +# If you want to run on a custom port, set an environment variable +export NGINX_PORT=5008 +docker run -it --rm -e NGINX_PORT=5008 -p 5008:5008 neo4jlabs/neodash .... ____ diff --git a/docs/modules/ROOT/pages/developer-guide/configuration.adoc b/docs/modules/ROOT/pages/developer-guide/configuration.adoc index 29664f00f..6df3fdfba 100644 --- a/docs/modules/ROOT/pages/developer-guide/configuration.adoc +++ b/docs/modules/ROOT/pages/developer-guide/configuration.adoc @@ -71,7 +71,7 @@ risk, as it exposes the Neo4j username to anyone who can access the NeoDash deployment. |standaloneDashboardName |string |My Dashboard |The exact name -(case-sensentive) of the dashboard to be loaded when running in +(case-sensitive) of the dashboard to be loaded when running in standalone mode. This must be a dashboard that is saved as a node in the graph. diff --git a/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc b/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc index 714e524f1..340c3c7d5 100644 --- a/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc +++ b/docs/modules/ROOT/pages/developer-guide/deploy-a-build.adoc @@ -27,6 +27,9 @@ This is an optional step if you want to configure optional settings for your Neo 1. Inside the folder you just unzipped, open up `config.json`. 2. Edit this file to modify your link:../configuration[Configuration] settings. 3. Save the file. +4. Inside the folder you just unzipped, open up `style.config.json`. +5. Edit this file to modify your link:../styleConfiguration[Style Configuration] settings. +6. Save the file == 3. Move the tarball/zip to your webserver Finally, copy the files to the correct folder on your webserver. @@ -34,7 +37,7 @@ Depending on the webserver type and version, this could be different directory. As an example - to copy the files to an nginx webserver using `scp`: ```bash -scp neodash-2.2.5 username@host:/usr/share/nginx/html +scp neodash-2.3.0 username@host:/usr/share/nginx/html ``` NeoDash should now be visible by visiting your (sub)domain in the browser. diff --git a/docs/modules/ROOT/pages/developer-guide/session-storage.adoc b/docs/modules/ROOT/pages/developer-guide/session-storage.adoc new file mode 100644 index 000000000..a4861a4cf --- /dev/null +++ b/docs/modules/ROOT/pages/developer-guide/session-storage.adoc @@ -0,0 +1,5 @@ += Session Storage + +This reducer serves only to store data that we want to reset at each new session. +To connect to it, just define a key and use the predefined actions to set a new pair (key,value) inside of it. +Inside the actions there is also an action to delete all the keys that match a precise prefix, it can be useful, for example, to wipe the sessionStorage state for a certain extension, if it stores the data inside the sessionStorage using a prefix (for example look at the query-translator extension at getSessionStorageHistoryKey). \ No newline at end of file diff --git a/docs/modules/ROOT/pages/developer-guide/state-management.adoc b/docs/modules/ROOT/pages/developer-guide/state-management.adoc index dc86315dc..c7513269d 100644 --- a/docs/modules/ROOT/pages/developer-guide/state-management.adoc +++ b/docs/modules/ROOT/pages/developer-guide/state-management.adoc @@ -11,7 +11,7 @@ structure: { "dashboard": { "title": "My Dashboard Name", - "version": "2.2", + "version": "2.3", "settings": { "pagenumber": 0, "editable": true, @@ -56,7 +56,7 @@ dashboard. Take the following simple dashboard as an example. { "dashboard": { "title": "A Simple Dashboard", - "version": "2.2", + "version": "2.3", "settings": { "pagenumber": 0, "editable": true, diff --git a/docs/modules/ROOT/pages/developer-guide/styleConfiguration.adoc b/docs/modules/ROOT/pages/developer-guide/styleConfiguration.adoc new file mode 100644 index 000000000..8aacd9aeb --- /dev/null +++ b/docs/modules/ROOT/pages/developer-guide/styleConfiguration.adoc @@ -0,0 +1,51 @@ += Style Configuration + +When using a custom NeoDash deployment, there are several theme variables that +can be configured. These mostly relate to css tokens for +link:https://cdn.jsdelivr.net/npm/@neo4j-ndl/base@1.4.0/lib/tokens/css/tokens.css[Needle] and some other brand specific options. + +For a simple (non-Dockerized) deployment, these configuration parameters +can be changed by modifying `dist/style.config.json` after you have built the +application. When Docker image, these can not be passed as environment +variables. + +An example configuration for NeoDash + +.... +{ + "DASHBOARD_HEADER_BRAND_LOGO": "logo_lightsand.png", + "APPLY_CUSTOM_BRAND_LOGO": true, + "DASHBOARD_HEADER_COLOR" : "#F3F3F0", + "DASHBOARD_HEADER_BUTTON_COLOR" : "#009999", + "DASHBOARD_HEADER_TITLE_COLOR" : "#00C1B6", + "DASHBOARD_PAGE_LIST_COLOR" : "#F3F3F0", + "DASHBOARD_PAGE_LIST_ACTIVE_COLOR": "#009999", + "style": { + "--palette-light-neutral-bg-weak" : "243, 243, 240" + } +} +.... + +== Configuration Options + +[width="100%",cols="19%,17%,26%,38%",options="header",] +|=== +|Name |Type |Default Value |Description +|APPLY_CUSTOM_BRAND_LOGO |boolean |false |If enabled, a custom logo will be used on the header based on the DASHBOARD_HEADER_BRAND_LOGO variable. + +|DASHBOARD_HEADER_BRAND_LOGO |string |undefined |If APPLY_CUSTOM_BRAND_LOGO is true, this variable defines the name of the logo file located on the public folder of the Neodash deployment. + +|DASHBOARD_HEADER_COLOR |string |#0B297D |Determines the color of the header. + +|DASHBOARD_HEADER_BUTTON_COLOR |string |#FFFFFF22 |Determines the color of the header buttons. + +|DASHBOARD_HEADER_TITLE_COLOR |string |#FFFFFF |Determines the color of the header title. + +|DASHBOARD_PAGE_LIST_COLOR |string |#F0F0F0 |Determines the color of the page selector tabs. + +|DASHBOARD_PAGE_LIST_ACTIVE_COLOR |string |#FFFFFF |Determines the color of the page selector active tabs. + +|style |object |{} | Determines css needle tokens that should be overridden at the root level. Colors should be defined with an rgb comma separated string (e.g "243, 243, 240") + + +|=== diff --git a/docs/modules/ROOT/pages/user-guide/extensions/index.adoc b/docs/modules/ROOT/pages/user-guide/extensions/index.adoc index d7657e872..349acd77f 100644 --- a/docs/modules/ROOT/pages/user-guide/extensions/index.adoc +++ b/docs/modules/ROOT/pages/user-guide/extensions/index.adoc @@ -16,7 +16,8 @@ The currently available extensions in NeoDash are: - link:advanced-visualizations[Advanced Visualizations] - link:rule-based-styling[Rule-based Styling] -- link:report-actions[Report Actions (Pro)] +- link:report-actions[Report Actions] +- link:natural-language-queries[Natural Language Queries] == Types of Extensions @@ -24,13 +25,10 @@ The currently available extensions in NeoDash are: Core Extensions are available as part of the open-source NeoDash project. These are available to use for free anywhere - Neo4j Desktop, public NeoDash deployments, and self-hosted NeoDash deployments. -=== 2. Pro Extensions -Pro Extensions are built by the Neo4j Professional Services team. These extensions are available to try out for free: - -1. In link:https://install.graphapp.io[NeoDash in Neo4j Desktop] -2. On link:https://neodash.graphapp.io[the Online Demo Environment] - -If you would like to use a pro extension in a self-hosted NeoDash environment, and have an Enterprise Neo4j License, reach out to link:mailto:ps_emea_pmo@neotechnology.com[Neo4j Professional Services] to discuss a commercial agreement. +=== 2. Expert Extensions +Expert Extensions are built by the Neo4j Professional Services team. +These extensions push NeoDash to the next level, by providing extra functionality to create interactive graph applications. +Reach out to link:mailto:emea_pmo@neotechnology.com[Neo4j Professional Services] if you are interested in a customized / new expert extension for your use-case. === 3. Custom Extensions Custom Extensions are self-built extensions that you can plug into the project. diff --git a/docs/modules/ROOT/pages/user-guide/extensions/natural-language-queries.adoc b/docs/modules/ROOT/pages/user-guide/extensions/natural-language-queries.adoc new file mode 100644 index 000000000..71530a055 --- /dev/null +++ b/docs/modules/ROOT/pages/user-guide/extensions/natural-language-queries.adoc @@ -0,0 +1,63 @@ += Natural Language Query Generation in NeoDash! +Use natural language to generate Cypher queries in NeoDash. Connect to an LLM through an API, and let NeoDash use your database schema + the report types to generate queries automatically. + +== Natural Language Queries +Natural Language Queries feature allows users to interact with NeoDash using natural language to generate Cypher queries for querying Neo4j graph databases. +This integration leverages Language Models (LLMs) to interpret user inputs and generate Cypher queries based on the provided schema definition. + +== Configuration +To enable Natural Language Queries in NeoDash, follow these configuration steps: + +1. Open NeoDash and navigate to the "Extensions" section in the left sidebar. +2. Locate the "Natural Language Queries" extension and click on it to activate it. +3. Once activated, a new button will appear in the sidebar(see image below). Click on the button to open the configuration window. +4. In the configuration window, you will be prompted to provide the necessary information to connect to the Language Model (LLM). Enter the model provider, API key, and select the desired model to use. +5. After providing the required information, click on the "Start Querying" button to finalize the configuration. + +image::extensionbutton.png[Extension Button enables Natural Language Queries button in the sidebar] + +image::llmconfiguration.png[Configuration settings for the Natural Language Queries extension] + +== Usage +Once the Natural Language Queries extension is configured, you can start using it in your NeoDash reports. Here's how: + +1. Open the Report settings for the desired report. +2. In the report settings, you will find a toggle switch located above the editor. This switch allows you to toggle between Cypher and English languages. +3. Since you have enabled the extension and authenticated by providing your API key, you can switch to the English language mode. +4. Start formulating your queries in plain English, using natural language expressions to describe the data you want to retrieve. +5. After composing your query, you have two options for further actions: + +* Translate: By clicking the "Translate" button, your query will be translated into Cypher using the Language Model. The translated Cypher query will be displayed in the editor when you toggle to the Cypher view. +This allows you to review and modify the generated Cypher query before execution. +* Run: If you wish to directly execute the query and view the results, click the "Run" button in the top right corner. The execution of the query will depend on the selected report type, and the results will be displayed accordingly. + +image::englisheditor.png[Example of the English editor in NeoDash] + +=== Here is how it works behind the scenes: +* Retrieve the Schema: The system prompts at the beginning of the interaction to retrieve the database schema. This ensures that the generated queries adhere to the provided schema and available relationship types and properties. + +* Prompting in English: Once the schema is retrieved, you can start prompting your queries in plain English. NeoDash, powered by the LLM, will interpret your English query and generate the corresponding Cypher query based on the provided schema. + +* Automatic Query Generation: NeoDash automatically generates the Cypher queries for you, taking into account the report type you specified. Whether it's a table, graph, bar chart, line chart, or any other supported report type, the generated queries will retrieve the necessary data based on the report requirements. + +* Retry Logic: To enhance the reliability of the generated queries, we have implemented retry logic. If there is any issue or error during the query generation process, the system will attempt to retry three times as a maximum and provide a valid query to ensure smooth query execution. + +== Prompting Tips + +When using Natural Language Queries in NeoDash, keep the following tips in mind to enhance your experience: + +1. Be clear and specific in your queries: Provide detailed descriptions of the data you want to retrieve, including node labels, relationship types, and property values. +2. Use keywords and phrases: Incorporate relevant keywords and phrases that are commonly used in the context of your data to improve query accuracy. +3. Ask precise questions: Frame your queries as questions to obtain specific information. For example, instead of "Show me all customers," try "Which customers have made a purchase in the last month?" +4. Experiment with different phrasings: If you're not getting the desired results, try rephrasing your query using synonyms or alternative expressions. +5. Avoid ambiguous queries: Ambiguous or vague queries may yield unexpected results. Make sure to provide sufficient context and clarify any ambiguities. +6. Validate and review generated queries: Always review the generated Cypher queries to ensure they accurately represent your intent and produce the expected results. + + +== Important Considerations + +When using Natural Language Queries with Language Models, it's important to be aware of the following considerations: + +1. Multiple model providers: Depending on your configuration, your queries may be processed by different model providers. Take into account that this means your data is being sent to different providers. +2. Non-deterministic nature: Language Models can produce non-deterministic outputs. The generated queries may vary between different runs, even with the same input prompt. Validate the generated queries and perform thorough testing to ensure correctness. +3. Potential hallucination: Language Models can generate outputs that may not align with the specific schema or data constraints. Exercise caution and verify the results to prevent potential inaccuracies or hallucinations. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/user-guide/extensions/report-actions.adoc b/docs/modules/ROOT/pages/user-guide/extensions/report-actions.adoc index d4f0fae4d..8b50f1651 100644 --- a/docs/modules/ROOT/pages/user-guide/extensions/report-actions.adoc +++ b/docs/modules/ROOT/pages/user-guide/extensions/report-actions.adoc @@ -39,4 +39,3 @@ Report Actions are available for the following report types: - Graphs - Maps -> This **Pro Extension** is free to try out in Neo4j Desktop, and the link:https://neodash.graphapp.io[NeoDash Demo Environment]. To use it in a self-hosted environment, reach out to link:mailto:ps_emea_pmo@neotechnology.com[Neo4j Professional Services] for a commercial agreement. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/user-guide/extensions/workflows.adoc b/docs/modules/ROOT/pages/user-guide/extensions/workflows.adoc new file mode 100644 index 000000000..2b95b06d5 --- /dev/null +++ b/docs/modules/ROOT/pages/user-guide/extensions/workflows.adoc @@ -0,0 +1,12 @@ += Workflows + +Introducing an advanced extension for creating, managing, and running workflows with Cypher queries. Simplify ETL flows, execute complex query chains, and run graph data science workloads effortlessly from Neodash. + +== Enable the extension + +== Create a Workflow + +== Create a new step in the workflow + +== Check status + diff --git a/docs/modules/ROOT/pages/user-guide/reports/bar-chart.adoc b/docs/modules/ROOT/pages/user-guide/reports/bar-chart.adoc index 24f431362..832e15950 100644 --- a/docs/modules/ROOT/pages/user-guide/reports/bar-chart.adoc +++ b/docs/modules/ROOT/pages/user-guide/reports/bar-chart.adoc @@ -25,8 +25,8 @@ image::bar.png[Basic Table] [source,cypher] ---- -Match (n:Person)-[e]->(m:Movie) -RETURN m.title, COUNT(p) as People, type(e) as Role +Match (p:Person)-[e]->(m:Movie) +RETURN m.title AS Title, COUNT(p) as People, type(e) as Role ---- image::barstacked.png[Basic Table] diff --git a/docs/modules/ROOT/pages/user-guide/reports/choropleth.adoc b/docs/modules/ROOT/pages/user-guide/reports/choropleth.adoc index 3824abaff..35fdbdd19 100644 --- a/docs/modules/ROOT/pages/user-guide/reports/choropleth.adoc +++ b/docs/modules/ROOT/pages/user-guide/reports/choropleth.adoc @@ -17,10 +17,9 @@ layout. It takes two fields: [source,cypher] ---- -MATCH (:Company{name:'NeoDash'})-[:HAS_DEPARTMENT]->(:Department)<-[:IN_DEPARTMENT]-(e:Employee), -(e)-[:LIVES_IN]->(c:Country) -WITH c.code as code, count(e) as value -RETURN code, value +MATCH p=(n:Wine)-[:IS_FROM|PART_OF*]->(c:Country) +WITH DISTINCT c.iso3 as country, count(DISTINCT n) as wines +RETURN country, wines ---- image::choropleth.png[Choropleth Chart] diff --git a/docs/modules/ROOT/pages/user-guide/reports/pie-chart.adoc b/docs/modules/ROOT/pages/user-guide/reports/pie-chart.adoc index d4321aa5c..e5979b32f 100644 --- a/docs/modules/ROOT/pages/user-guide/reports/pie-chart.adoc +++ b/docs/modules/ROOT/pages/user-guide/reports/pie-chart.adoc @@ -16,7 +16,7 @@ value of the pie. See *Advanced Settings* for more information. [source,cypher] ---- -Match (n:Person)-[e]->(m:Movie) +Match (p:Person)-[e]->(m:Movie) RETURN m.title as Title, COUNT(p) as People LIMIT 8 ---- diff --git a/docs/modules/ROOT/pages/user-guide/reports/table.adoc b/docs/modules/ROOT/pages/user-guide/reports/table.adoc index a3137f3ae..2c8fe5559 100644 --- a/docs/modules/ROOT/pages/user-guide/reports/table.adoc +++ b/docs/modules/ROOT/pages/user-guide/reports/table.adoc @@ -20,7 +20,7 @@ Double-clicking on a table cell will copy that cell's value to the user's clipbo .... MATCH (n:Movie)<-[:ACTED_IN]-(p:Person) -RETURN n.title, n.released, count(p) as actors +RETURN n.title AS Title, n.released AS Released, count(p) as Actors .... image::table1.png[Basic Table] diff --git a/docs/server.js b/docs/server.js index 339be95f5..33333b02b 100644 --- a/docs/server.js +++ b/docs/server.js @@ -1,7 +1,7 @@ const express = require('express') const app = express() -const version = "2.2" +const version = "2.3" app.use(express.static('./build/site')) app.get('/', (req, res) => res.redirect('neodash/' + version)) app.listen(8000, () => console.log('📘 http://localhost:8000')) \ No newline at end of file diff --git a/gallery/yarn.lock b/gallery/yarn.lock index d9c3afb48..309d5fd87 100644 --- a/gallery/yarn.lock +++ b/gallery/yarn.lock @@ -8929,9 +8929,9 @@ toidentifier@1.0.1: integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== tough-cookie@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" - integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== + 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" diff --git a/package.json b/package.json index f9dd83840..f712990c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "neodash", - "version": "2.2.5", + "version": "2.3.0", "description": "NeoDash - Neo4j Dashboard Builder", "neo4jDesktop": { "apiVersion": "^1.2.0" @@ -23,7 +23,7 @@ "scripts": { "dev": "yarn webpack-dev-server --mode development", "debug": "yarn --node-options='--inspect' webpack-dev-server --mode development", - "build": "yarn webpack --mode production && cp -r public/* dist/", + "build": "yarn webpack --mode production --env production && cp -r public/* dist/", "build-minimal": "yarn webpack --mode production --env production && cp -r public/* dist/", "format": "prettier --write \"**/*.{ts,tsx}\"", "lint": "eslint --ext .ts --ext .tsx .", @@ -34,27 +34,30 @@ "keywords": [], "author": "Neo4j Labs", "dependencies": { - "@codemirror/lang-markdown": "^6.0.5", - "@codemirror/language-data": "^6.1.0", - "@material-ui/core": "^4.12.4", - "@material-ui/icons": "^4.11.3", - "@material-ui/lab": "^4.0.0-alpha.60", - "@material-ui/styles": "^4.11.4", - "@mui/material": "^5.3.0", - "@mui/x-data-grid": "5.10.0", + "@codemirror/lang-markdown": "^6.1.1", + "@codemirror/language-data": "^6.3.1", + "@mui/icons-material": "^5.11.16", + "@mui/material": "^5.12.3", + "@mui/styles": "^5.12.3", + "@mui/x-data-grid": "5.17.26", "@mui/x-date-pickers": "^5.0.17", - "@neo4j-cypher/react-codemirror": "^1.0.0", - "@nivo/bar": "^0.80.0", - "@nivo/circle-packing": "^0.80.0", - "@nivo/core": "^0.80.0", - "@nivo/geo": "^0.80.0", - "@nivo/line": "^0.80.0", - "@nivo/pie": "^0.80.0", - "@nivo/radar": "^0.80.0", - "@nivo/sankey": "^0.80.0", - "@nivo/sunburst": "^0.80.0", - "@nivo/treemap": "^0.80.0", + "@neo4j-cypher/react-codemirror": "^1.0.2", + "@neo4j-ndl/base": "1.7.0", + "@neo4j-ndl/react": "1.7.0", + "@nivo/bar": "^0.82.1", + "@nivo/circle-packing": "^0.82.1", + "@nivo/core": "^0.82.1", + "@nivo/geo": "^0.82.1", + "@nivo/line": "^0.82.1", + "@nivo/pie": "^0.82.1", + "@nivo/radar": "^0.82.1", + "@nivo/sankey": "^0.82.1", + "@nivo/scatterplot": "^0.83.0", + "@nivo/sunburst": "^0.82.1", + "@nivo/treemap": "^0.82.1", + "@sentry/react": "^7.57.0", "babel-runtime": "^6.26.0", + "chroma-js": "^2.4.2", "classnames": "^2.3.1", "d3-scale-chromatic": "^3.0.0", "dayjs": "^1.11.7", @@ -62,14 +65,19 @@ "leaflet": "^1.7.1", "lodash.debounce": "^4.0.8", "lodash.isequal": "^4.5.0", - "material-ui-color-picker": "^3.5.1", - "mui-nested-menu": "^3.2.0", + "mui-color": "^2.0.0-beta.2", + "mui-nested-menu": "^3.2.1", "neo4j-client-sso": "^1.2.2", + "openai": "^3.3.0", + "postcss": "^8.4.21", + "postcss-loader": "^7.2.4", + "postcss-preset-env": "^8.3.0", + "prop-types": "^15.8.1", "react": "^17.0.2", "react-cool-dimensions": "^2.0.7", "react-dom": "^17.0.2", "react-force-graph-2d": "^1.23.8", - "react-gauge-chart": "^0.4.0", + "react-gauge-chart": "^0.4.1", "react-grid-layout": "^1.3.4", "react-leaflet": "^3.2.5", "react-leaflet-cluster": "^1.0.4", @@ -77,11 +85,13 @@ "react-leaflet-heatmap-layer-v3": "^3.0.3-beta-1", "react-markdown": "^8.0.0", "react-redux": "^7.2.6", + "react-show-more-text": "^1.6.2", "react-use-error-boundary": "^3.0.0", "redux-persist": "^6.0.0", "redux-thunk": "^2.4.1", "remark-gfm": "^3.0.1", - "reselect": "^4.1.5", + "reselect": "^4.1.8", + "tailwindcss": "^3.3.2", "use-neo4j": "^0.3.13", "yaml": "^2.2.1" }, @@ -93,14 +103,17 @@ "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", "@babel/register": "^7.16.9", + "@cypress/code-coverage": "^3.10.8", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10", "@redux-devtools/extension": "^3.2.3", "@typescript-eslint/eslint-plugin": "^5.42.0", "@typescript-eslint/parser": "^5.42.0", "babel-loader": "^8.2.3", + "babel-plugin-istanbul": "^6.1.1", "css-loader": "^3.6.0", - "cypress": "^9.5.3", + "cypress": "^10.11.0", "eslint": "^8.26.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-import": "^2.26.0", @@ -110,13 +123,13 @@ "husky": "^8.0.1", "lint-staged": "^13.0.3", "prettier": "^2.7.1", - "react-hot-loader": "^4.13.0", + "react-refresh": "^0.14.0", "serverless-finch": "^4.0.0", "source-map-loader": "^4.0.0", "style-loader": "^1.1.3", "styled-components": "^5.3.3", "typescript": "^4.8.4", - "webpack": "^5.67.0", + "webpack": "^5.77.0", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.7.3" } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 000000000..f94d52e21 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +const tailwindcss = require('tailwindcss'); + +module.exports = { + plugins: ['postcss-preset-env', tailwindcss], +}; diff --git a/public/config.json b/public/config.json index 685055b4c..6a203041f 100644 --- a/public/config.json +++ b/public/config.json @@ -1,12 +1,12 @@ { - "ssoEnabled": false, - "ssoDiscoveryUrl": "https://example.com", - "standalone": false, - "standaloneProtocol": "neo4j", - "standaloneHost": "localhost", - "standalonePort": "7687", - "standaloneDatabase": "neo4j", - "standaloneDashboardName": "My Dashboard", - "standaloneDashboardDatabase": "dashboards", - "standaloneDashboardURL": "" -} \ No newline at end of file + "ssoEnabled": false, + "ssoDiscoveryUrl": "https://example.com", + "standalone": false, + "standaloneProtocol": "neo4j", + "standaloneHost": "localhost", + "standalonePort": "7687", + "standaloneDatabase": "neo4j", + "standaloneDashboardName": "My Dashboard", + "standaloneDashboardDatabase": "dashboards", + "standaloneDashboardURL": "" +} diff --git a/public/style.config.json b/public/style.config.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/public/style.config.json @@ -0,0 +1 @@ +{} diff --git a/public/style.css b/public/style.css index 897c043a4..a0a93e449 100644 --- a/public/style.css +++ b/public/style.css @@ -1,203 +1,231 @@ +/* Needle */ +.logo-btn.large .ndl-icon { + width: 36px !important; + height: 36px !important; +} + +.ndl-modal hr { + margin-top: 0.5em !important; + margin-bottom: 0.5em !important; +} + +.centered { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.MuiInputBase-root { + font-family: 'Nunito Sans', sans-serif !important; +} +/* End Needle */ + .MuiDrawer-paper { - position: relative !important; + position: relative !important; } .blue-grey { - background: #607d8b !important; - color: white !important; + background: #607d8b !important; + color: white !important; } -.no-underline [class*='MuiInput-underline-']::before{ - border-bottom: none; +.no-underline .MuiInput-underline::before { + border-bottom: none; } .MuiContainer-root { - padding-left: 10px !important; - padding-right: 10px !important; + padding-left: 0px !important; + padding-right: 0px !important; +} + +.MuiFormControl-root { + padding-top: 0px; } .large input { - font-size: 20px; - margin-top: -6px; + font-size: 20px; + margin-top: -6px; } .MuiChip-root { - border-radius: 16px; + border-radius: 16px !important; } .CodeMirror-lint-message-error { - background-image: none !important; + background-image: none !important; } .leaflet-custom-node-popup { - margin-left: 1px; - margin-bottom: 34px !important; + margin-left: 1px; + margin-bottom: 34px !important; } .leaflet-custom-rel-popup { - margin-left: 0px; + margin-left: 0px; } .leaflet-control-attribution { - display: none; + display: none; } -.leaflet-custom-tooltip {} - -.leaflet-marker-icon { - width: 50px !important; - margin-left: -25px !important; +.leaflet-custom-tooltip { } -.autosize .cm-editor { - height: auto; +.leaflet-marker-icon { + width: 50px !important; + margin-left: -25px !important; } /* Hack to make the table header smaller, TODO - clean this up */ .table-small-header { - height: 36px; + height: 36px; } .MuiDataGrid-root { - border: none !important; + border: none !important; } .MuiChip-root:before { - border: none !important; + border: none !important; } .react-resizable-handle { - bottom: 1px !important; - opacity: 0.5; - color: rgb(199, 199, 199); + bottom: 1px !important; + opacity: 0.5; + color: rgb(222, 222, 222); } .MuiDataGrid-footerContainer { - border: none !important; + border: none !important; } .neodash-card-editable-false .react-resizable-handle { - display: none; -} - -.react-grid-item>.react-resizable-handle.react-resizable-handle-se { - cursor: nwse-resize !important; + display: none; } -.react-grid-item>.react-resizable-handle::after { - border-right: 2px solid rgba(0, 0, 0, 0.4) !important; - border-bottom: 2px solid rgba(0, 0, 0, 0.4) !important; +.react-grid-item > .react-resizable-handle.react-resizable-handle-se { + cursor: nwse-resize !important; } -/* .MuiDataGrid-columnHeaders { - min-height: 32px !important; - max-height: 32px !important; - line-height: 32px !important; +.react-grid-item > .react-resizable-handle::after { + border-right: 2px solid rgba(0, 0, 0, 0.4) !important; + border-bottom: 2px solid rgba(0, 0, 0, 0.4) !important; } -.MuiDataGrid-columnSeparator{ - height: 32px; -} -.MuiDataGrid-columnHeaderTitleContainer { - padding-left: 1px !important; -} -.MuiDataGrid-window{ - top: 32px !important; - overflow-y: hidden !important; - overflow-x: hidden !important; -} -.MuiTablePagination-root{ - margin-top: -10px; -} */ .MuiDataGrid-footerContainer { - border-top: none !important; -} -.chrome-picker { - margin-top: -285px; - margin-left: 10px; + border-top: none !important; } .MuiTablePagination-root { - margin-top: -10px; + margin-top: -10px; } .MuiDataGrid-virtualScroller { - overflow-y: hidden !important; + overflow-y: hidden !important; } +.MuiCard-root { + box-shadow: 0 0 #0000,0 0 #0000,var(--tw-shadow) !important; + box-shadow: var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow) !important; +} + +.white-text { + color: white !important; +} .MuiCardHeader-content .MuiInputBase-root.Mui-disabled { - color: inherit !important; + color: inherit !important; } .MuiCardHeader-content .MuiInput-underline.Mui-disabled:before { - border-bottom-style: none !important; + border-bottom-style: none !important; } .textinput-linenumbers { - scrollbar-width: none; - resize: none; - background: url(linenumbers.png); - background-size: 20; - background-attachment: local; - background-repeat: no-repeat; - font-family: monospace; - font-size: 14px; - line-height: 16px; - border-color: #fff; - width: calc(100% + 30px); - display: block; - background-size: 26px; - white-space: pre; - background-position: 0px -11px; - /*line-height: 1.2em;*/ - /* margin-left: -15px !important; */ - padding-right: 0px !important; - /* margin-right: -35px !important; */ - margin-top: 0px !important; - padding-left: 30px; - padding-top: 0px !important; - padding-bottom: 0px !important; - margin-bottom: 0px !important; - overflow-x: scroll !important; - overflow-y: scroll; - min-height: 116px; - /*height: 200px !important;*/ + scrollbar-width: none; + resize: none; + background: url(linenumbers.png); + background-size: 20; + background-attachment: local; + background-repeat: no-repeat; + font-family: monospace; + font-size: 14px; + line-height: 16px; + border-color: #fff; + width: calc(100% + 30px); + display: block; + background-size: 26px; + white-space: pre; + background-position: 0px -11px; + padding-right: 0px !important; + margin-top: 0px !important; + padding-left: 30px; + padding-top: 0px !important; + padding-bottom: 0px !important; + margin-bottom: 0px !important; + overflow-x: scroll !important; + overflow-y: scroll; + min-height: 116px; + /*height: 200px !important;*/ } .textinput-linenumbers::-webkit-scrollbar { - display: none; + display: none; } .MuiDrawer-docked .MuiDrawer-paper { - overflow-x: hidden; + overflow-x: hidden; } #center-aligned { - text-align: center; + text-align: center; } + .card-view.expanded { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: white; - z-index: 1299; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: white; + z-index: 1299; } .force-graph-container .graph-tooltip { - color: black !important; - background: none !important; + color: black !important; + background: none !important; } .not-animated .react-grid-item.cssTransforms { - transition-property: none !important; + transition-property: none !important; } .react-grid-layout { - overflow-x: hidden; + overflow-x: hidden; } .cm-tooltip-autocomplete { - margin-top: 4px; + margin-top: 4px; +} + +.card-view .MuiTablePagination-root { + margin-top: -40px; + } + +@keyframes pulse { + 0% { + transform: scale(0.95); + box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7); + } + + 70% { + transform: scale(1); + box-shadow: 0 0 0 10px rgba(0, 0, 0, 0); + } + + 100% { + transform: scale(0.95); + box-shadow: 0 0 0 0 rgba(0, 0, 0, 0); + } +} \ No newline at end of file diff --git a/public/translator.png b/public/translator.png new file mode 100644 index 000000000..59df348f1 Binary files /dev/null and b/public/translator.png differ diff --git a/release-notes.md b/release-notes.md index 900d5c758..7c2ca4a0d 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,6 +1,29 @@ -## NeoDash 2.2.5 -This is a minor release with some small bug fixes, directly following the 2.2.4 release. -- Fixed replacement rules for parameters in iFrames/Markdown reports. [#417](https://github.com/neo4j-labs/neodash/pull/417) -- Added automatic header text color switch for reports with a dark background [#420](https://github.com/neo4j-labs/neodash/pull/420) -- Fixed handling right click events (for graph exploration) in Neo4j Desktop [#415](https://github.com/neo4j-labs/neodash/pull/415). -- Added support for unweighted Sankey charts [#419](https://github.com/neo4j-labs/neodash/pull/419) +## NeoDash 2.3.0 +NeoDash 2.3 is out! This release brings a brand new look-and-feel, improved speed for large dashboards, and a new extension for querying Neo4j with natural language (using LLMs). + +Highlights: +- Write **[Natural Language Queries](https://neo4j.com/labs/neodash/2.3/user-guide/extensions/natural-language-queries/)** and use OpenAI to generate Cypher queries for your visualizations. (OpenAI API key required) +- UI updated to use the **[Neo4j Design Language](https://www.neo4j.design/)**, giving NeoDash a similar look-and-feel to other Neo4j tools. +- Customize branding, colors dynamically with a new [Style Configuration File](https://neo4j.com/labs/neodash/2.3/developer-guide/style-configuration). + +Other changes: +- Fixed issues with date picker / free-text parameter sometimes not initializing. +- Improved documentation by fixing broken links, and adding more details around complex concepts. +- **Pro Extensions have evolved to open Expert Extensions.** +- Fixed issue where deep-linked parameters were not set from the URL. +- Added option to specify absolute width for table columns (in pixels or as percentages). +- Fixed map charts to auto-cluster markers when they collide, or are too close together. +- ... and dozens of other improvements! + + + +Contributors to this release: +- [Alfredo Rubin](https://github.com/alfredorubin96) +- [Harold Agudelo](https://github.com/BennuFire) +- [Aleksandar Simeunovic](https://github.com/AleSim94) +- [Marius Conjeaud](https://github.com/mariusconjeaud) +- [Brahm Prakash Mishra](https://github.com/brahmprakashMishra) +- [Pierre Martignon](https://github.com/pierremartignon) +- [Kim Zachariassen](https://github.com/KiZach) +- [Paolo Baldini](https://github.com/8Rav3n) +- [Niels de Jong](https://github.com/nielsdejong/) diff --git a/scripts/docker-neo4j-initializer/docker-neo4j.sh b/scripts/docker-neo4j-initializer/docker-neo4j.sh index fb1fc862b..cc805ac95 100644 --- a/scripts/docker-neo4j-initializer/docker-neo4j.sh +++ b/scripts/docker-neo4j-initializer/docker-neo4j.sh @@ -2,5 +2,5 @@ docker run \ --name neo4j \ -p7474:7474 -p7687:7687 \ -d \ - --env NEO4J_AUTH=neo4j/test \ + --env NEO4J_AUTH=neo4j/test1234 \ neo4j:4.4 \ No newline at end of file diff --git a/scripts/docker-neo4j-initializer/start-movies-db.sh b/scripts/docker-neo4j-initializer/start-movies-db.sh index 553d66fe4..247cb8428 100644 --- a/scripts/docker-neo4j-initializer/start-movies-db.sh +++ b/scripts/docker-neo4j-initializer/start-movies-db.sh @@ -1,3 +1,3 @@ echo "Loading Dataset" -cat ./scripts/docker-neo4j-initializer/movies.cypher | docker exec --interactive neo4j bin/cypher-shell -u neo4j -p test -echo "MATCH () RETURN count(*)" | docker exec --interactive neo4j bin/cypher-shell -u neo4j -p test \ No newline at end of file +cat ./scripts/docker-neo4j-initializer/movies.cypher | docker exec --interactive neo4j bin/cypher-shell -u neo4j -p test1234 +echo "MATCH () RETURN count(*)" | docker exec --interactive neo4j bin/cypher-shell -u neo4j -p test1234 \ No newline at end of file diff --git a/scripts/message-entrypoint.sh b/scripts/message-entrypoint.sh index ab0474d46..3fb003ef9 100644 --- a/scripts/message-entrypoint.sh +++ b/scripts/message-entrypoint.sh @@ -1,7 +1,7 @@ #!/bin/sh ########### -echo '-----------------------------------------------------------------------------------------' -echo '| NeoDash is available on http://localhost:5005 by default. |' -echo '| Make sure your ports are mapped correctly (-p 5005:5005) when starting the container. |' -echo '-----------------------------------------------------------------------------------------' +echo "-----------------------------------------------------------------------------------------" +echo "| NeoDash is available on http://localhost:$NGINX_PORT by default. |" +echo "| Make sure your ports are mapped correctly (-p ${NGINX_PORT}:${NGINX_PORT}) when starting the container. |" +echo "-----------------------------------------------------------------------------------------" diff --git a/src/application/Application.tsx b/src/application/Application.tsx index df5e7db8f..83963daf7 100644 --- a/src/application/Application.tsx +++ b/src/application/Application.tsx @@ -1,10 +1,6 @@ -import React from 'react'; -import { hot } from 'react-hot-loader/root'; -import CssBaseline from '@material-ui/core/CssBaseline'; +import React, { useEffect } from 'react'; import NeoNotificationModal from '../modal/NotificationModal'; import NeoWelcomeScreenModal from '../modal/WelcomeScreenModal'; -import { ThemeProvider } from '@material-ui/styles'; -import { lightTheme } from '../component/theme/Themes'; import { connect } from 'react-redux'; import { applicationGetConnection, @@ -31,8 +27,10 @@ import { clearNotification, resetShareDetails, setAboutModalOpen, + setCachedSSODiscoveryUrl, setConnected, setConnectionModalOpen, + setConnectionProperties, setOldDashboard, setReportHelpModalOpen, setWaitForSSO, @@ -48,6 +46,10 @@ import { loadDashboardThunk } from '../dashboard/DashboardThunks'; import { NeoLoadSharedDashboardModal } from '../modal/LoadSharedDashboardModal'; import { downloadComponentAsImage } from '../chart/ChartUtils'; import NeoReportHelpModal from '../modal/ReportHelpModal'; +import '@neo4j-ndl/base/lib/neo4j-ds-styles.css'; +import { ThemeProvider } from '@mui/material/styles'; +import lightTheme from '../component/theme/Themes'; +import { resetSessionStorage } from '../sessionStorage/SessionStorageActions'; /** * This is the main application component for NeoDash. @@ -74,6 +76,7 @@ const Application = ({ shareDetails, createConnection, createConnectionFromDesktopIntegration, + setConnectionDetails, onResetShareDetails, onConfirmLoadSharedDashboard, initializeApplication, @@ -90,22 +93,23 @@ const Application = ({ }) => { const [initialized, setInitialized] = React.useState(false); - if (!initialized) { - // Tell Neo4j Desktop to disable capturing right clicking - window.neo4jDesktopApi && - window.neo4jDesktopApi.showMenuOnRightClick && - window.neo4jDesktopApi.showMenuOnRightClick(false); - setInitialized(true); - initializeApplication(initialized); - } + useEffect(() => { + if (!initialized) { + // Tell Neo4j Desktop to disable capturing right clicking + window.neo4jDesktopApi && + window.neo4jDesktopApi.showMenuOnRightClick && + window.neo4jDesktopApi.showMenuOnRightClick(false); + setInitialized(true); + initializeApplication(initialized); + } + }, []); const ref = React.useRef(); // Only render the dashboard component if we have an active Neo4j connection. return ( -
- +
{/* TODO - clean this up. Only draw the placeholder if the connection is not established. */} {connected ? downloadComponentAsImage(ref)}> : <>} @@ -120,6 +124,7 @@ const Application = ({ standaloneSettings={standaloneSettings} createConnection={createConnection} onSSOAttempt={onSSOAttempt} + setConnectionProperties={setConnectionDetails} onConnectionModalClose={onConnectionModalClose} > ({ const mapDispatchToProps = (dispatch) => ({ createConnection: (protocol, url, port, database, username, password) => { dispatch(setConnected(false)); + dispatch(resetSessionStorage()); dispatch(createConnectionThunk(protocol, url, port, database, username, password)); }, createConnectionFromDesktopIntegration: () => { @@ -192,8 +198,12 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(setWelcomeScreenOpen(true)); dispatch(resetShareDetails()); }, - onSSOAttempt: (_) => { + onSSOAttempt: (discoveryUrlValidated) => { dispatch(setWaitForSSO(true)); + dispatch(setCachedSSODiscoveryUrl(discoveryUrlValidated)); + }, + setConnectionDetails: (protocol, url, port, database, username, password) => { + dispatch(setConnectionProperties(protocol, url, port, database, username, password)); }, onConfirmLoadSharedDashboard: (_) => dispatch(onConfirmLoadSharedDashboardThunk()), onConnectionModalOpen: (_) => dispatch(setConnectionModalOpen(true)), @@ -206,4 +216,4 @@ const mapDispatchToProps = (dispatch) => ({ Application.displayName = 'Application'; -export default connect(mapStateToProps, mapDispatchToProps)(hot(Application)); +export default connect(mapStateToProps, mapDispatchToProps)(Application); diff --git a/src/application/ApplicationActions.ts b/src/application/ApplicationActions.ts index 61c3384e5..49311d768 100644 --- a/src/application/ApplicationActions.ts +++ b/src/application/ApplicationActions.ts @@ -113,10 +113,23 @@ export const setShareDetailsFromUrl = ( database: string, username: string, password: string, - dashboardDatabase: string + dashboardDatabase: string, + skipConfirmation: boolean ) => ({ type: SET_SHARE_DETAILS_FROM_URL, - payload: { type, id, standalone, protocol, url, port, database, username, password, dashboardDatabase }, + payload: { + type, + id, + standalone, + protocol, + url, + port, + database, + username, + password, + dashboardDatabase, + skipConfirmation, + }, }); export const SET_STANDALONE_ENABLED = 'APPLICATION/SET_STANDALONE_ENABLED'; @@ -171,6 +184,12 @@ export const setWaitForSSO = (wait: boolean) => ({ payload: { wait }, }); +export const SET_CACHED_SSO_DISCOVERY_URL = 'APPLICATION/SET_CACHED_SSO_DISCOVERY_URL'; +export const setCachedSSODiscoveryUrl = (url: string) => ({ + type: SET_CACHED_SSO_DISCOVERY_URL, + payload: { url }, +}); + export const SET_SESSION_PARAMETERS = 'APPLICATION/SET_SESSION_PARAMETERS'; export const setSessionParameters = (parameters: any) => ({ type: SET_SESSION_PARAMETERS, diff --git a/src/application/ApplicationReducer.ts b/src/application/ApplicationReducer.ts index 75677ca82..38f470fe2 100644 --- a/src/application/ApplicationReducer.ts +++ b/src/application/ApplicationReducer.ts @@ -9,6 +9,7 @@ import { CREATE_NOTIFICATION, RESET_SHARE_DETAILS, SET_ABOUT_MODAL_OPEN, + SET_CACHED_SSO_DISCOVERY_URL, SET_CONNECTED, SET_CONNECTION_MODAL_OPEN, SET_CONNECTION_PROPERTIES, @@ -196,8 +197,25 @@ export const applicationReducer = (state = initialState, action: { type: any; pa state = update(state, { shareDetails: undefined }); return state; } + case SET_CACHED_SSO_DISCOVERY_URL: { + const { url } = payload; + state = update(state, { cachedSSODiscoveryUrl: url }); + return state; + } case SET_SHARE_DETAILS_FROM_URL: { - const { type, id, standalone, protocol, url, port, database, username, password, dashboardDatabase } = payload; + const { + type, + id, + standalone, + protocol, + url, + port, + database, + username, + password, + dashboardDatabase, + skipConfirmation, + } = payload; state = update(state, { shareDetails: { type: type, @@ -210,6 +228,7 @@ export const applicationReducer = (state = initialState, action: { type: any; pa username: username, password: password, dashboardDatabase: dashboardDatabase, + skipConfirmation: skipConfirmation, }, }); return state; diff --git a/src/application/ApplicationSelectors.ts b/src/application/ApplicationSelectors.ts index 354f3b60c..263fae4bf 100644 --- a/src/application/ApplicationSelectors.ts +++ b/src/application/ApplicationSelectors.ts @@ -65,6 +65,7 @@ export const applicationGetSsoSettings = (state: any) => { return { ssoEnabled: state.application.ssoEnabled, ssoDiscoveryUrl: state.application.ssoDiscoveryUrl, + cachedSSODiscoveryUrl: state.application.cachedSSODiscoveryUrl, }; }; diff --git a/src/application/ApplicationThunks.ts b/src/application/ApplicationThunks.ts index cbbb4db90..bbe18fe5c 100644 --- a/src/application/ApplicationThunks.ts +++ b/src/application/ApplicationThunks.ts @@ -9,6 +9,7 @@ import { loadDashboardThunk, upgradeDashboardVersion, } from '../dashboard/DashboardThunks'; +import { setExtensionSidebarOpen } from '../extensions/sidebar/state/SidebarActions'; import { createNotificationThunk } from '../page/PageThunks'; import { runCypherQuery } from '../report/ReportQueryRunner'; import { @@ -208,6 +209,8 @@ export const handleSharedDashboardsThunk = () => (dispatch: any) => { const id = decodeURIComponent(urlParams.get('id')); const type = urlParams.get('type'); const standalone = urlParams.get('standalone') == 'Yes'; + const skipConfirmation = urlParams.get('skipConfirmation') == 'Yes'; + const dashboardDatabase = urlParams.get('dashboardDatabase'); if (urlParams.get('credentials')) { const connection = decodeURIComponent(urlParams.get('credentials')); @@ -243,12 +246,19 @@ export const handleSharedDashboardsThunk = () => (dispatch: any) => { database, username, password, - dashboardDatabase + dashboardDatabase, + skipConfirmation ) ); + + if (skipConfirmation === true) { + dispatch(onConfirmLoadSharedDashboardThunk()); + } + window.history.pushState({}, document.title, '/'); } else { dispatch(setConnectionModalOpen(false)); + // dispatch(setWelcomeScreenOpen(false)); dispatch( setShareDetailsFromUrl( type, @@ -260,7 +270,8 @@ export const handleSharedDashboardsThunk = () => (dispatch: any) => { undefined, undefined, undefined, - undefined + undefined, + false ) ); window.history.pushState({}, document.title, '/'); @@ -365,9 +376,9 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: dispatch(setPageNumberThunk(parseInt(page))); } } - - dispatch(setSSOEnabled(config.ssoEnabled, config.ssoDiscoveryUrl)); const state = getState(); + dispatch(setSSOEnabled(config.ssoEnabled, state.application.cachedSSODiscoveryUrl)); + const { standalone } = config; dispatch( setStandaloneEnabled( @@ -384,6 +395,8 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: ) ); dispatch(setConnectionModalOpen(false)); + // TODO - generalize this, close all drawer-based extensions on app startup. + dispatch(setExtensionSidebarOpen(false)); // Auto-upgrade the dashboard version if an old version is cached. if (state.dashboard && state.dashboard.version !== NEODASH_VERSION) { @@ -407,6 +420,16 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: ) ); } + if (state.dashboard.version == '2.2') { + const upgradedDashboard = upgradeDashboardVersion(state.dashboard, '2.2', '2.3'); + dispatch(setDashboard(upgradedDashboard)); + dispatch( + createNotificationThunk( + 'Successfully upgraded dashboard', + 'Your old dashboard was migrated to version 2.3. You might need to refresh this page.' + ) + ); + } } // At the load of a dashboard, we want to ensure correct casting types dispatch(updateParametersToNeo4jTypeThunk()); @@ -417,8 +440,9 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: dispatch(setAboutModalOpen(false)); dispatch(setConnected(false)); dispatch(setWelcomeScreenOpen(false)); - const success = await initializeSSO(config.ssoDiscoveryUrl, (credentials) => { + const success = await initializeSSO(state.application.cachedSSODiscoveryUrl, (credentials) => { if (standalone) { + // Redirected from SSO and running in viewer mode, merge retrieved config with hardcoded credentials. dispatch( setConnectionProperties( config.standaloneProtocol, @@ -439,6 +463,21 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: credentials.password ) ); + } else { + // Redirected from SSO and running in editor mode, merge retrieved config with existing details. + dispatch( + setConnectionProperties( + state.application.connection.protocol, + state.application.connection.url, + state.application.connection.port, + state.application.connection.database, + credentials.username, + credentials.password + ) + ); + } + + if (standalone) { if (config.standaloneDashboardURL !== undefined && config.standaloneDashboardURL.length > 0) { dispatch(setDashboardToLoadAfterConnecting(config.standaloneDashboardURL)); } else { @@ -449,7 +488,7 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: }); dispatch(setWaitForSSO(false)); if (!success) { - alert('Unable to connect using SSO'); + alert('Unable to connect using SSO. See the browser console for more details.'); dispatch( createNotificationThunk( 'Unable to connect using SSO', @@ -467,6 +506,7 @@ export const loadApplicationConfigThunk = () => async (dispatch: any, getState: dispatch(initializeApplicationAsEditorThunk(config, paramsToSetAfterConnecting)); } } catch (e) { + console.log(e); dispatch(setWelcomeScreenOpen(false)); dispatch( createNotificationThunk( diff --git a/src/card/Card.tsx b/src/card/Card.tsx index 00198e3cf..fb529325a 100644 --- a/src/card/Card.tsx +++ b/src/card/Card.tsx @@ -1,5 +1,4 @@ -import Card from '@material-ui/core/Card'; -import Collapse from '@material-ui/core/Collapse'; +import { Card, Collapse, debounce } from '@mui/material'; import React, { useCallback, useContext, useEffect, useState } from 'react'; import NeoCardSettings from './settings/CardSettings'; import NeoCardView from './view/CardView'; @@ -16,7 +15,6 @@ import { } from './CardThunks'; import { toggleReportSettings } from './CardActions'; import { getReportState } from './CardSelectors'; -import { debounce, Dialog, DialogContent } from '@material-ui/core'; import { getDashboardIsEditable, getDatabase, @@ -30,11 +28,12 @@ import { loadDatabaseListFromNeo4jThunk } from '../dashboard/DashboardThunks'; import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; import { getDashboardExtensions } from '../dashboard/DashboardSelectors'; import { downloadComponentAsImage } from '../chart/ChartUtils'; +import { Dialog } from '@neo4j-ndl/react'; import { createNotificationThunk } from '../page/PageThunks'; const NeoCard = ({ - index, // index of the card. - report, // state of the card, retrieved based on card index. + id, // id of the card. + report, // state of the card, retrieved based on card id. editable, // whether the card is editable. database, // the neo4j database that the card is running against. extensions, // A set of enabled extensions. @@ -95,7 +94,7 @@ const NeoCard = ({ const onToggleCardExpand = () => { // When we re-minimize a card, close the settings to avoid position issues. if (expanded && settingsOpen) { - onToggleCardSettings(index, false); + onToggleCardSettings(id, false); } setExpanded(!expanded); }; @@ -120,17 +119,21 @@ const NeoCard = ({ // TODO - get rid of some of the props-drilling here... const component = ( -
+
{/* The front of the card, referred to as the 'view' */} - - + + onReportSettingUpdate(index, name, value)} + updateReportSetting={(name, value) => onReportSettingUpdate(id, name, value)} createNotification={(title, message) => createNotification(title, message)} type={report.type} database={database} @@ -147,21 +150,23 @@ const NeoCard = ({ expanded={expanded} onToggleCardExpand={onToggleCardExpand} onGlobalParameterUpdate={onGlobalParameterUpdate} - onSelectionUpdate={(selectable, field) => onSelectionUpdate(index, selectable, field)} - onTitleUpdate={(title) => onTitleUpdate(index, title)} - onFieldsUpdate={(fields) => onFieldsUpdate(index, fields)} + onSelectionUpdate={(selectable, field) => onSelectionUpdate(id, selectable, field)} + onTitleUpdate={(title) => onTitleUpdate(id, title)} + onFieldsUpdate={(fields) => onFieldsUpdate(id, fields)} onToggleCardSettings={() => { setSettingsOpen(true); setCollapseTimeout('auto'); - debouncedOnToggleCardSettings(index, true); + debouncedOnToggleCardSettings(id, true); }} /> {/* The back of the card, referred to as the 'settings' */} - - + + onQueryUpdate(index, query)} - onDatabaseChanged={(database) => onDatabaseChanged(index, database)} - onReportSettingUpdate={(setting, value) => onReportSettingUpdate(index, setting, value)} - onTypeUpdate={(type) => onTypeUpdate(index, type)} + onQueryUpdate={(query) => onQueryUpdate(id, query)} + onDatabaseChanged={(database) => onDatabaseChanged(id, database)} + onReportSettingUpdate={(setting, value) => onReportSettingUpdate(id, setting, value)} + onTypeUpdate={(type) => onTypeUpdate(id, type)} onReportHelpButtonPressed={() => onReportHelpButtonPressed()} - onRemovePressed={() => onRemovePressed(index)} - onClonePressed={() => onClonePressed(index)} + onRemovePressed={() => onRemovePressed(id)} + onClonePressed={() => onClonePressed(id)} onToggleCardSettings={() => { setSettingsOpen(false); setCollapseTimeout('auto'); - debouncedOnToggleCardSettings(index, false); + debouncedOnToggleCardSettings(id, false); }} - onToggleReportSettings={() => onToggleReportSettings(index)} + onToggleReportSettings={() => onToggleReportSettings(id)} /> @@ -202,15 +207,8 @@ const NeoCard = ({ // Look into React Portals: https://stackoverflow.com/questions/61432878/how-to-render-child-component-outside-of-its-parent-component-dom-hierarchy if (expanded) { return ( - - - {component} - + + {component} ); } @@ -218,50 +216,50 @@ const NeoCard = ({ }; const mapStateToProps = (state, ownProps) => ({ - report: getReportState(state, ownProps.index), + report: getReportState(state, ownProps.id), extensions: getDashboardExtensions(state), editable: getDashboardIsEditable(state), database: getDatabase( state, ownProps && ownProps.dashboardSettings ? ownProps.dashboardSettings.pagenumber : undefined, - ownProps.index + ownProps.id ), globalParameters: { ...getGlobalParameters(state), ...getSessionParameters(state) }, }); const mapDispatchToProps = (dispatch) => ({ - onTitleUpdate: (index: any, title: any) => { - dispatch(updateReportTitleThunk(index, title)); + onTitleUpdate: (id: any, title: any) => { + dispatch(updateReportTitleThunk(id, title)); }, - onQueryUpdate: (index: any, query: any) => { - dispatch(updateReportQueryThunk(index, query)); + onQueryUpdate: (id: any, query: any) => { + dispatch(updateReportQueryThunk(id, query)); }, - onTypeUpdate: (index: any, type: any) => { - dispatch(updateReportTypeThunk(index, type)); + onTypeUpdate: (id: any, type: any) => { + dispatch(updateReportTypeThunk(id, type)); }, - onReportSettingUpdate: (index: any, setting: any, value: any) => { - dispatch(updateReportSettingThunk(index, setting, value)); + onReportSettingUpdate: (id: any, setting: any, value: any) => { + dispatch(updateReportSettingThunk(id, setting, value)); }, - onFieldsUpdate: (index: any, fields: any) => { - dispatch(updateFieldsThunk(index, fields)); + onFieldsUpdate: (id: any, fields: any) => { + dispatch(updateFieldsThunk(id, fields)); }, onGlobalParameterUpdate: (key: any, value: any) => { dispatch(updateGlobalParameterThunk(key, value)); }, - onSelectionUpdate: (index: any, selectable: any, field: any) => { - dispatch(updateSelectionThunk(index, selectable, field)); + onSelectionUpdate: (id: any, selectable: any, field: any) => { + dispatch(updateSelectionThunk(id, selectable, field)); }, - onToggleCardSettings: (index: any, open: any) => { - dispatch(toggleCardSettingsThunk(index, open)); + onToggleCardSettings: (id: any, open: any) => { + dispatch(toggleCardSettingsThunk(id, open)); }, onReportHelpButtonPressed: () => { dispatch(setReportHelpModalOpen(true)); }, - onToggleReportSettings: (index: any) => { - dispatch(toggleReportSettings(index)); + onToggleReportSettings: (id: any) => { + dispatch(toggleReportSettings(id)); }, - onDatabaseChanged: (index: any, database: any) => { - dispatch(updateReportDatabaseThunk(index, database)); + onDatabaseChanged: (id: any, database: any) => { + dispatch(updateReportDatabaseThunk(id, database)); }, createNotification: (title: any, message: any) => { dispatch(createNotificationThunk(title, message)); diff --git a/src/card/CardActions.ts b/src/card/CardActions.ts index 3b3828878..a09c22cdd 100644 --- a/src/card/CardActions.ts +++ b/src/card/CardActions.ts @@ -3,85 +3,85 @@ */ export const TOGGLE_CARD_SETTINGS = 'PAGE/CARD/TOGGLE_CARD_SETTINGS'; -export const toggleCardSettings = (pagenumber: any, index: any, open: any) => ({ +export const toggleCardSettings = (pagenumber: any, id: any, open: any) => ({ type: TOGGLE_CARD_SETTINGS, - payload: { pagenumber, index, open }, + payload: { pagenumber, id, open }, }); export const HARD_RESET_CARD_SETTINGS = 'PAGE/CARD/HARD_RESET_CARD_SETTINGS'; -export const hardResetCardSettings = (pagenumber: any, index: any) => ({ +export const hardResetCardSettings = (pagenumber: any, id: any) => ({ type: HARD_RESET_CARD_SETTINGS, - payload: { pagenumber, index }, + payload: { pagenumber, id }, }); export const UPDATE_REPORT_TITLE = 'PAGE/CARD/UPDATE_REPORT_TITLE'; -export const updateReportTitle = (pagenumber: number, index: number, title: any) => ({ +export const updateReportTitle = (pagenumber: number, id: number, title: any) => ({ type: UPDATE_REPORT_TITLE, - payload: { pagenumber, index, title }, + payload: { pagenumber, id, title }, }); export const UPDATE_REPORT_SIZE = 'PAGE/CARD/UPDATE_REPORT_SIZE'; -export const updateReportSize = (pagenumber: number, index: number, width: any, height: any) => ({ +export const updateReportSize = (pagenumber: number, id: number, width: any, height: any) => ({ type: UPDATE_REPORT_SIZE, - payload: { pagenumber, index, width, height }, + payload: { pagenumber, id, width, height }, }); export const UPDATE_REPORT_QUERY = 'PAGE/CARD/UPDATE_REPORT_QUERY'; -export const updateReportQuery = (pagenumber: number, index: number, query: any) => ({ +export const updateReportQuery = (pagenumber: number, id: number, query: any) => ({ type: UPDATE_REPORT_QUERY, - payload: { pagenumber, index, query }, + payload: { pagenumber, id, query }, }); export const UPDATE_CYPHER_PARAMETERS = 'PAGE/CARD/UPDATE_CYPHER_PARAMETERS'; -export const updateCypherParameters = (pagenumber: number, index: number, parameters: any) => ({ +export const updateCypherParameters = (pagenumber: number, id: number, parameters: any) => ({ type: UPDATE_CYPHER_PARAMETERS, - payload: { pagenumber, index, parameters }, + payload: { pagenumber, id, parameters }, }); export const UPDATE_REPORT_TYPE = 'PAGE/CARD/UPDATE_REPORT_TYPE'; -export const updateReportType = (pagenumber: number, index: number, type: any) => ({ +export const updateReportType = (pagenumber: number, id: number, type: any) => ({ type: UPDATE_REPORT_TYPE, - payload: { pagenumber, index, type }, + payload: { pagenumber, id, type }, }); export const UPDATE_FIELDS = 'PAGE/CARD/UPDATE_FIELDS'; -export const updateFields = (pagenumber: number, index: number, fields: any) => ({ +export const updateFields = (pagenumber: number, id: number, fields: any) => ({ type: UPDATE_FIELDS, - payload: { pagenumber, index, fields }, + payload: { pagenumber, id, fields }, }); export const UPDATE_SELECTION = 'PAGE/CARD/UPDATE_SELECTION'; -export const updateSelection = (pagenumber: number, index: number, selectable: any, field: any) => ({ +export const updateSelection = (pagenumber: number, id: number, selectable: any, field: any) => ({ type: UPDATE_SELECTION, - payload: { pagenumber, index, selectable, field }, + payload: { pagenumber, id, selectable, field }, }); export const UPDATE_ALL_SELECTIONS = 'PAGE/CARD/UPDATE_ALL_SELECTIONS'; -export const updateAllSelections = (pagenumber: number, index: number, selections: any) => ({ +export const updateAllSelections = (pagenumber: number, id: number, selections: any) => ({ type: UPDATE_ALL_SELECTIONS, - payload: { pagenumber, index, selections }, + payload: { pagenumber, id, selections }, }); export const CLEAR_SELECTION = 'PAGE/CARD/CLEAR_SELECTION'; -export const clearSelection = (pagenumber: number, index: number) => ({ +export const clearSelection = (pagenumber: number, id: number) => ({ type: CLEAR_SELECTION, - payload: { pagenumber, index }, + payload: { pagenumber, id }, }); export const UPDATE_REPORT_SETTING = 'PAGE/CARD/UPDATE_REPORT_SETTING'; -export const updateReportSetting = (pagenumber: number, index: number, setting: any, value: any) => ({ +export const updateReportSetting = (pagenumber: number, id: number, setting: any, value: any) => ({ type: UPDATE_REPORT_SETTING, - payload: { pagenumber, index, setting, value }, + payload: { pagenumber, id, setting, value }, }); export const TOGGLE_REPORT_SETTINGS = 'PAGE/CARD/TOGGLE_REPORT_SETTINGS'; -export const toggleReportSettings = (index: any) => ({ +export const toggleReportSettings = (id: any) => ({ type: TOGGLE_REPORT_SETTINGS, - payload: { index }, + payload: { id }, }); export const UPDATE_REPORT_DATABASE = 'PAGE/CARD/UPDATE_REPORT_DATABASE'; -export const updateReportDatabase = (pagenumber: number, index: number, database: any) => ({ +export const updateReportDatabase = (pagenumber: number, id: number, database: any) => ({ type: UPDATE_REPORT_DATABASE, - payload: { pagenumber, index, database }, + payload: { pagenumber, id, database }, }); diff --git a/src/card/CardAddButton.tsx b/src/card/CardAddButton.tsx index d92be2f76..522fc506d 100644 --- a/src/card/CardAddButton.tsx +++ b/src/card/CardAddButton.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { connect } from 'react-redux'; -import { Card, CardContent, Typography, Fab } from '@material-ui/core'; -import AddIcon from '@material-ui/icons/Add'; +import { Card, CardContent } from '@mui/material'; +import { IconButton } from '@neo4j-ndl/react'; +import { SquaresPlusIconOutline } from '@neo4j-ndl/react/icons'; /** * Button to add a new report to the current page. @@ -9,20 +10,19 @@ import AddIcon from '@material-ui/icons/Add'; const NeoAddNewCard = ({ onCreatePressed }) => { return (
- + - - { - onCreatePressed(); - }} - > - - - + { + onCreatePressed(); + }} + size='large' + floating + > + +
diff --git a/src/card/CardReducer.ts b/src/card/CardReducer.ts index ef49b8506..cd9dde11e 100644 --- a/src/card/CardReducer.ts +++ b/src/card/CardReducer.ts @@ -14,6 +14,7 @@ import { UPDATE_REPORT_DATABASE, } from './CardActions'; import { TOGGLE_CARD_SETTINGS } from './CardActions'; +import { createUUID } from '../dashboard/DashboardThunks'; const update = (state, mutations) => Object.assign({}, state, mutations); @@ -22,6 +23,7 @@ const update = (state, mutations) => Object.assign({}, state, mutations); */ export const CARD_INITIAL_STATE = { + id: createUUID(), title: '', query: '\n\n\n', settingsOpen: false, diff --git a/src/card/CardSelectors.ts b/src/card/CardSelectors.ts index e4df95472..b7ed4d27e 100644 --- a/src/card/CardSelectors.ts +++ b/src/card/CardSelectors.ts @@ -1,6 +1,6 @@ export const getDashboardTitle = (state: any) => state.dashboard.title; -export const getReportState = (state: any, index: any) => { +export const getReportState = (state: any, id: any) => { const { pagenumber } = state.dashboard.settings; - return state.dashboard.pages[pagenumber].reports[index]; + return state.dashboard.pages[pagenumber].reports.find((o) => o.id === id); }; diff --git a/src/card/CardThunks.ts b/src/card/CardThunks.ts index c2d8bd715..1c5efd052 100644 --- a/src/card/CardThunks.ts +++ b/src/card/CardThunks.ts @@ -17,11 +17,11 @@ import isEqual from 'lodash.isequal'; import { SELECTION_TYPES } from '../config/CardConfig'; import { getSelectionBasedOnFields } from '../chart/ChartUtils'; -export const updateReportTitleThunk = (index, title) => (dispatch: any, getState: any) => { +export const updateReportTitleThunk = (id, title) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(updateReportTitle(pagenumber, index, title)); + dispatch(updateReportTitle(pagenumber, id, title)); } catch (e) { dispatch(createNotificationThunk('Cannot update report title', e)); } @@ -30,55 +30,56 @@ export const updateReportTitleThunk = (index, title) => (dispatch: any, getState /* Thunk used to update the database used from a report */ -export const updateReportDatabaseThunk = (index, database) => (dispatch: any, getState: any) => { +export const updateReportDatabaseThunk = (id, database) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(updateReportDatabase(pagenumber, index, database)); + dispatch(updateReportDatabase(pagenumber, id, database)); } catch (e) { dispatch(createNotificationThunk('Cannot update report database', e)); } }; -export const updateReportQueryThunk = (index, query) => (dispatch: any, getState: any) => { +export const updateReportQueryThunk = (id, query) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(updateReportQuery(pagenumber, index, query)); + dispatch(updateReportQuery(pagenumber, id, query)); } catch (e) { dispatch(createNotificationThunk('Cannot update query', e)); } }; -export const updateCypherParametersThunk = (index, parameters) => (dispatch: any, getState: any) => { +export const updateCypherParametersThunk = (id, parameters) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(updateCypherParameters(pagenumber, index, parameters)); + dispatch(updateCypherParameters(pagenumber, id, parameters)); } catch (e) { dispatch(createNotificationThunk('Cannot update cypher parameters rate', e)); } }; -export const updateReportTypeThunk = (index, type) => (dispatch: any, getState: any) => { +export const updateReportTypeThunk = (id, type) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(updateReportType(pagenumber, index, type)); - dispatch(updateFields(pagenumber, index, [])); - dispatch(clearSelection(pagenumber, index)); + dispatch(updateReportType(pagenumber, id, type)); + dispatch(updateFields(pagenumber, id, [])); + dispatch(clearSelection(pagenumber, id)); } catch (e) { dispatch(createNotificationThunk('Cannot update report type', e)); } }; -export const updateFieldsThunk = (index, fields) => (dispatch: any, getState: any) => { +export const updateFieldsThunk = (id, fields) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - const { extensions } = state.dashboard; - const oldReport = state.dashboard.pages[pagenumber].reports[index]; + const extensions = Object.fromEntries(Object.entries(state.dashboard.extensions).filter(([_, v]) => v.active)); + const oldReport = state.dashboard.pages[pagenumber].reports.find((o) => o.id === id); + if (!oldReport) { return; } @@ -100,74 +101,74 @@ export const updateFieldsThunk = (index, fields) => (dispatch: any, getState: an } else if (selectableFields[selection].optional) { // If the fields change, always set optional selections to none. if (selectableFields[selection].multiple) { - dispatch(updateSelection(pagenumber, index, selection, ['(none)'])); + dispatch(updateSelection(pagenumber, id, selection, ['(none)'])); } else { - dispatch(updateSelection(pagenumber, index, selection, '(none)')); + dispatch(updateSelection(pagenumber, id, selection, '(none)')); } } else if (fields.length > 0) { // For multi selections, select the Nth item of the result fields as a single item array. if (selectableFields[selection].multiple) { // only update if the old selection no longer covers the new set of fields... if (!oldSelection[selection] || !oldSelection[selection].every((v) => fields.includes(v))) { - dispatch(updateSelection(pagenumber, index, selection, [fields[Math.min(i, fields.length - 1)]])); + dispatch(updateSelection(pagenumber, id, selection, [fields[Math.min(i, fields.length - 1)]])); } } else if (selectableFields[selection].type == SELECTION_TYPES.NODE_PROPERTIES) { // For node property selections, select the most obvious properties of the node to display. const selection = getSelectionBasedOnFields(fields, oldSelection, autoAssignSelectedProperties); - dispatch(updateAllSelections(pagenumber, index, selection)); + dispatch(updateAllSelections(pagenumber, id, selection)); } else { // Else, default the selection to the Nth item of the result set fields. - dispatch(updateSelection(pagenumber, index, selection, fields[Math.min(i, fields.length - 1)])); + dispatch(updateSelection(pagenumber, id, selection, fields[Math.min(i, fields.length - 1)])); } } }); // Set the new set of fields for the report so that we may select them. - dispatch(updateFields(pagenumber, index, fields)); + dispatch(updateFields(pagenumber, id, fields)); } } catch (e) { dispatch(createNotificationThunk('Cannot update report fields', e)); } }; -export const updateSelectionThunk = (index, selectable, field) => (dispatch: any, getState: any) => { +export const updateSelectionThunk = (id, selectable, field) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(updateSelection(pagenumber, index, selectable, field)); + dispatch(updateSelection(pagenumber, id, selectable, field)); } catch (e) { dispatch(createNotificationThunk('Cannot update report selection', e)); } }; -export const toggleCardSettingsThunk = (index, open) => (dispatch: any, getState: any) => { +export const toggleCardSettingsThunk = (id, open) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(toggleCardSettings(pagenumber, index, open)); + dispatch(toggleCardSettings(pagenumber, id, open)); } catch (e) { dispatch(createNotificationThunk('Cannot open card settings', e)); } }; -export const updateReportSettingThunk = (index, setting, value) => (dispatch: any, getState: any) => { +export const updateReportSettingThunk = (id, setting, value) => (dispatch: any, getState: any) => { try { const state = getState(); - const { extensions } = state.dashboard; + const extensions = Object.fromEntries(Object.entries(state.dashboard.extensions).filter(([_, v]) => v.active)); const { pagenumber } = state.dashboard.settings; // If we disable optional selections (e.g. grouping), we reset these selections to their none value. if (setting == 'showOptionalSelections' && value == false) { - const reportType = state.dashboard.pages[pagenumber].reports[index].type; + const reportType = state.dashboard.pages[pagenumber].reports.find((o) => o.id === id).type; const reportTypes = getReportTypes(extensions); const selectableFields = reportTypes[reportType].selection; const optionalSelectables = selectableFields ? Object.keys(selectableFields).filter((key) => selectableFields[key].optional) : []; optionalSelectables.forEach((selection) => { - dispatch(updateSelection(pagenumber, index, selection, '(none)')); + dispatch(updateSelection(pagenumber, id, selection, '(none)')); }); } - dispatch(updateReportSetting(pagenumber, index, setting, value)); + dispatch(updateReportSetting(pagenumber, id, setting, value)); } catch (e) { dispatch(createNotificationThunk('Error when updating report settings', e)); } diff --git a/src/card/settings/CardSettings.tsx b/src/card/settings/CardSettings.tsx index 92100b579..df7f56f2b 100644 --- a/src/card/settings/CardSettings.tsx +++ b/src/card/settings/CardSettings.tsx @@ -3,11 +3,13 @@ import { ReportItemContainer } from '../CardStyle'; import NeoCardSettingsHeader from './CardSettingsHeader'; import NeoCardSettingsContent from './CardSettingsContent'; import NeoCardSettingsFooter from './CardSettingsFooter'; -import { CardContent } from '@material-ui/core'; +import { CardContent } from '@mui/material'; import { CARD_HEADER_HEIGHT } from '../../config/CardConfig'; const NeoCardSettings = ({ settingsOpen, + pagenumber, + reportId, query, database, // Current database related to the report databaseList, // List of databases the user can choose from ('system' is filtered out) @@ -53,6 +55,8 @@ const NeoCardSettings = ({ // TODO - instead of hiding everything based on settingsopen, only hide the components that slow down render (cypher editor) const cardSettingsContent = settingsOpen ? ( ) : ( - + ); const cardSettingsFooter = settingsOpen ? ( @@ -85,9 +89,9 @@ const NeoCardSettings = ({ ); return ( -
+
{cardSettingsHeader} - + {cardSettingsContent} {cardSettingsFooter} diff --git a/src/card/settings/CardSettingsContent.tsx b/src/card/settings/CardSettingsContent.tsx index 129ca0e81..362be7a5c 100644 --- a/src/card/settings/CardSettingsContent.tsx +++ b/src/card/settings/CardSettingsContent.tsx @@ -1,13 +1,20 @@ import React, { useEffect } from 'react'; -import CardContent from '@material-ui/core/CardContent'; -import MenuItem from '@material-ui/core/MenuItem'; +import CardContent from '@mui/material/CardContent'; import debounce from 'lodash/debounce'; import { useCallback } from 'react'; -import NeoField from '../../component/field/Field'; -import NeoCodeEditorComponent from '../../component/editor/CodeEditorComponent'; +import NeoCodeEditorComponent, { + DEFAULT_CARD_SETTINGS_HELPER_TEXT_STYLE, +} from '../../component/editor/CodeEditorComponent'; import { getReportTypes } from '../../extensions/ExtensionUtils'; +import { Dropdown } from '@neo4j-ndl/react'; +import { + EXTENSIONS_CARD_SETTINGS_COMPONENT, + getExtensionCardSettingsComponents, +} from '../../extensions/ExtensionConfig'; const NeoCardSettingsContent = ({ + pagenumber, + reportId, query, database, // Current report database databaseList, // List of databases the user can choose from ('system' is filtered out) @@ -37,37 +44,97 @@ const NeoCardSettingsContent = ({ const reportTypes = getReportTypes(extensions); const SettingsComponent = reportTypes[type] && reportTypes[type].settingsComponent; + function hasExtensionComponents() { + return ( + Object.keys(EXTENSIONS_CARD_SETTINGS_COMPONENT).filter( + (name) => extensions[name] && EXTENSIONS_CARD_SETTINGS_COMPONENT[name] + ).length > 0 + ); + } + + function updateCypherQuery(value) { + debouncedQueryUpdate(value); + setQueryText(value); + } + + function renderExtensionsComponents() { + const res = ( + <> + {Object.keys(EXTENSIONS_CARD_SETTINGS_COMPONENT).map((name) => { + const Component = extensions[name] ? EXTENSIONS_CARD_SETTINGS_COMPONENT[name] : ''; + return Component ? ( + + ) : ( + <> + ); + })} + + ); + return res; + } + + const defaultQueryBoxComponent = ( + <> + { + updateCypherQuery(value); + }} + placeholder={`Enter Cypher here...`} + /> +
{reportTypes[type] && reportTypes[type].helperText}
+ + ); + return ( - - onTypeUpdate(value)} - choices={Object.keys(reportTypes).map((option) => ( - - {reportTypes[option].label} - - ))} + + + newValue && onTypeUpdate(Object.keys(reportTypes).find((key) => reportTypes[key].label === newValue.value)), + options: Object.keys(reportTypes).map((option) => ({ + label: reportTypes[option].label, + value: reportTypes[option].label, + })), + value: { label: reportTypes[type].label, value: reportTypes[type].label }, + menuPortalTarget: document.querySelector('body'), + }} + fluid + style={{ marginLeft: '0px', marginRight: '10px', width: '47%', maxWidth: '200px', display: 'inline-block' }} /> {reportTypes[type] && reportTypes[type].disableDatabaseSelector == undefined ? ( - ( - - {database} - - ))} - onChange={(value) => { - setDatabaseText(value); - debouncedDatabaseUpdate(value); + placeholder='neo4j' + type='select' + selectProps={{ + onChange: (newValue) => { + newValue && setDatabaseText(newValue.value); + newValue && debouncedDatabaseUpdate(newValue.value); + }, + options: databaseList.map((database) => ({ + label: database, + value: database, + })), + value: { label: databaseText, value: databaseText }, + menuPortalTarget: document.querySelector('body'), }} + fluid + style={{ marginLeft: '0px', marginRight: '10px', width: '47%', maxWidth: '200px', display: 'inline-block' }} /> ) : ( <> @@ -86,31 +153,7 @@ const NeoCardSettingsContent = ({ onQueryUpdate={onQueryUpdate} /> ) : ( -
- { - debouncedQueryUpdate(value); - setQueryText(value); - }} - placeholder={'Enter Cypher here...'} - /> -

- {reportTypes[type] && reportTypes[type].helperText} -

-
+
{hasExtensionComponents() ? renderExtensionsComponents() : defaultQueryBoxComponent}
)}
); diff --git a/src/card/settings/CardSettingsFooter.tsx b/src/card/settings/CardSettingsFooter.tsx index 52d5165cc..1c86d6b0f 100644 --- a/src/card/settings/CardSettingsFooter.tsx +++ b/src/card/settings/CardSettingsFooter.tsx @@ -1,15 +1,18 @@ import React, { useEffect } from 'react'; import debounce from 'lodash/debounce'; import { useCallback } from 'react'; -import { FormControlLabel, FormGroup, IconButton, Switch, Tooltip } from '@material-ui/core'; +import { FormGroup, Tooltip } from '@mui/material'; import NeoSetting from '../../component/field/Setting'; import { NeoCustomReportStyleModal, RULE_BASED_REPORT_CUSTOMIZATIONS, } from '../../extensions/styling/StyleRuleCreationModal'; -import TuneIcon from '@material-ui/icons/Tune'; import { getReportTypes } from '../../extensions/ExtensionUtils'; -import StarsIcon from '@material-ui/icons/Stars'; +import { RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS } from '../../extensions/actions/ActionsRuleCreationModal'; +import NeoCustomReportActionsModal from '../../extensions/actions/ActionsRuleCreationModal'; +import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; +import { AdjustmentsHorizontalIconOutline, SparklesIconOutline } from '@neo4j-ndl/react/icons'; +import { IconButton, Switch } from '@neo4j-ndl/react'; const update = (state, mutations) => Object.assign({}, state, mutations); @@ -28,6 +31,10 @@ const NeoCardSettingsFooter = ({ const [customReportStyleModalOpen, setCustomReportStyleModalOpen] = React.useState(false); const settingToCustomize = 'styleRules'; + // Variables related to customizing report actions + const [customReportActionsModalOpen, setCustomReportActionsModalOpen] = React.useState(false); + const actionsToCustomize = 'actionsRules'; + const debouncedReportSettingUpdate = useCallback(debounce(onReportSettingUpdate, 250), []); const updateSpecificReportSetting = (field: string, value: any) => { @@ -108,9 +115,10 @@ const NeoCardSettingsFooter = ({ ); // TODO - Make the extensions more pluggable and dynamic, instead of hardcoded here. + // ^ keep modals at a higher level in the object hierarchy instead of injecting in the footer. return (
- {extensions.styling ? ( + {extensions.styling && extensions.styling.active ? ( )} + {extensions.actions && extensions.actions.active ? ( + + ) : ( + <> + )} + {editable ? ( ) : ( <> @@ -95,6 +95,9 @@ const NeoCardViewHeader = ({ setText(event.target.value); debouncedTitleUpdate(event.target.value); }} + size={'small'} + style={{ paddingTop: '0px important!' }} + variant={'standard'} /> @@ -107,47 +110,47 @@ const NeoCardViewHeader = ({ // TODO: all components like buttons should probably be seperate files const settingsButton = ( - - - + + + ); const refreshButton = ( - - - + + + ); const maximizeButton = ( - - - + + + ); const unMaximizeButton = ( - - + + ); const downloadImageButton = ( - - - + + + ); const descriptionButton = ( - - setDescriptionModalOpen(true)} aria-label='details'> - + + setDescriptionModalOpen(true)} aria-label='details' clean size='medium'> + ); @@ -162,9 +165,13 @@ const NeoCardViewHeader = ({ > {title} - setDescriptionModalOpen(false)} style={{ padding: '3px', float: 'right' }}> + setDescriptionModalOpen(false)} + style={{ padding: '3px', float: 'right' }} + aria-label={'rect badge'} + > - + diff --git a/src/chart/ChartUtils.ts b/src/chart/ChartUtils.ts index aa14c538e..046ad0be5 100644 --- a/src/chart/ChartUtils.ts +++ b/src/chart/ChartUtils.ts @@ -94,7 +94,11 @@ export function valueIsObject(value) { return className == 'Object'; } -export function toNumber({ low, high }) { +export function toNumber(ref) { + if (ref === undefined) { + return ref; + } + let { low, high } = ref; let res = high; for (let i = 0; i < 32; i++) { @@ -342,10 +346,6 @@ export const flatten = (data) => export const processHierarchyFromRecords = (records: Record[], selection: any) => { return records.reduce((data: Record, row: Record) => { try { - // const index = recordToNative(row.get('index')); - // const key = recordToNative(row.get('key')); - // const value = recordToNative(row.get('value')); - const index = recordToNative(row.get(selection.index)); // const idx = data.findIndex(item => item.index === index) // const key = selection['key'] !== "(none)" ? recordToNative(row.get(selection['key'])) : selection['value']; diff --git a/src/chart/SettingsUtils.ts b/src/chart/SettingsUtils.ts index d7436d542..5be5f0952 100644 --- a/src/chart/SettingsUtils.ts +++ b/src/chart/SettingsUtils.ts @@ -29,6 +29,7 @@ export const getSettings = ( userSettings && userSettings.styleRules, getGlobalParameter ); - + settings.actionsRules = + extensionEnabled(extensions, 'actions') && settings && userSettings.actionsRules ? userSettings.actionsRules : []; return settings; }; diff --git a/src/chart/Utils.ts b/src/chart/Utils.ts index 1b5b0882d..cc0c4a984 100644 --- a/src/chart/Utils.ts +++ b/src/chart/Utils.ts @@ -84,3 +84,30 @@ export const flatten = (data) => } return [...acc, item]; }, []); + +export const rgbaToHex = (color: string): string => { + let rgba; + if (/^rgb/.test(color)) { + rgba = color.replace(/^rgba?\(|\s+|\)$/g, '').split(','); + } else { + rgba = color.split(','); + } + + if (rgba) { + // rgb to hex + // eslint-disable-next-line no-bitwise + let hex = `#${((1 << 24) + (parseInt(rgba[0], 10) << 16) + (parseInt(rgba[1], 10) << 8) + parseInt(rgba[2], 10)) + .toString(16) + .slice(1)}`; + + // added alpha param if exists + if (rgba[4]) { + const alpha = Math.round(0o1 * 255); + const hexAlpha = (alpha + 0x10000).toString(16).substr(-2).toUpperCase(); + hex += hexAlpha; + } + + return hex; + } + return color; +}; diff --git a/src/chart/bar/BarChart.tsx b/src/chart/bar/BarChart.tsx index 7aa6e194b..101a2a9eb 100644 --- a/src/chart/bar/BarChart.tsx +++ b/src/chart/bar/BarChart.tsx @@ -1,14 +1,9 @@ -import { ResponsiveBar } from '@nivo/bar'; +import { ResponsiveBar, ResponsiveBarCanvas } from '@nivo/bar'; import React, { useEffect } from 'react'; import { NoDrawableDataErrorMessage } from '../../component/editor/CodeViewerComponent'; import { getD3ColorsByScheme } from '../../config/ColorConfig'; import { extensionEnabled } from '../../extensions/ExtensionUtils'; -import { - evaluateRulesOnDict, - styleRulesReplaceParams, - identifyStyleRuleParameters, - useStyleRules, -} from '../../extensions/styling/StyleRuleEvaluator'; +import { evaluateRulesOnDict, useStyleRules } from '../../extensions/styling/StyleRuleEvaluator'; import { ChartProps } from '../Chart'; import { convertRecordObjectToString, recordToNative } from '../ChartUtils'; @@ -29,55 +24,64 @@ const NeoBarChart = (props: ChartProps) => { }, 1); return () => clearTimeout(timeOutId); }, [props.selection]); - if (loading) { - return <>; - } const { records, selection } = props; - if (!selection || props.records == null || props.records.length == 0 || props.records[0].keys == null) { - return ; - } + const [keys, setKeys] = React.useState({}); + const [data, setData] = React.useState[]>([]); - const keys = {}; - const data: Record[] = records - .reduce((data: Record[], row: Record) => { - try { - if (!selection || !selection.index || !selection.value) { - return data; - } - const index = convertRecordObjectToString(row.get(selection.index)); - const idx = data.findIndex((item) => item.index === index); + useEffect(() => { + let newKeys = {}; + let newData: Record[] = records + .reduce((data: Record[], row: Record) => { + try { + if (!selection || !selection.index || !selection.value) { + return data; + } + const index = convertRecordObjectToString(row.get(selection.index)); + const idx = data.findIndex((item) => item.index === index); - const key = selection.key !== '(none)' ? recordToNative(row.get(selection.key)) : selection.value; - const value = recordToNative(row.get(selection.value)); + const key = selection.key !== '(none)' ? recordToNative(row.get(selection.key)) : selection.value; + const rawValue = recordToNative(row.get(selection.value)); + const value = rawValue !== null ? rawValue : 0.0000001; + if (isNaN(value)) { + return data; + } + newKeys[key] = true; - if (isNaN(value)) { + if (idx > -1) { + data[idx][key] = value; + } else { + data.push({ index, [key]: value }); + } return data; + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + return []; } - keys[key] = true; - - if (idx > -1) { - data[idx][key] = value; - } else { - data.push({ index, [key]: value }); - } - return data; - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - return []; - } - }, []) - .map((row) => { - Object.keys(keys).forEach((key) => { - // eslint-disable-next-line no-prototype-builtins - if (!row.hasOwnProperty(key)) { - row[key] = 0; - } + }, []) + .map((row) => { + Object.keys(newKeys).forEach((key) => { + // eslint-disable-next-line no-prototype-builtins + if (!row.hasOwnProperty(key)) { + row[key] = 0; + } + }); + return row; }); - return row; - }); + + setKeys(newKeys); + setData(newData); + }, [selection]); + + if (loading) { + return <>; + } + + if (!selection || props.records == null || props.records.length == 0 || props.records[0].keys == null) { + return ; + } const settings = props.settings ? props.settings : {}; const legendWidth = settings.legendWidth ? settings.legendWidth : 128; @@ -107,7 +111,6 @@ const NeoBarChart = (props: ChartProps) => { ); const chartColorsByScheme = getD3ColorsByScheme(colorScheme); - // Compute bar color based on rules - overrides default color scheme completely. const getBarColor = (bar) => { let { data, id } = bar; @@ -130,10 +133,6 @@ const NeoBarChart = (props: ChartProps) => { return chartColorsByScheme[colorIndex]; }; - if (data.length == 0) { - return ; - } - const BarComponent = ({ bar, borderColor }) => { let shade = false; let darkTop = false; @@ -201,15 +200,21 @@ const NeoBarChart = (props: ChartProps) => { ); }; - // TODO: Get rid of duplicate pie slice names... + + // Fixing canvas bug, from https://github.com/plouc/nivo/issues/2162 + HTMLCanvasElement.prototype.getBBox = function tooltipMapper() { + return { width: this.offsetWidth, height: this.offsetHeight }; + }; const extraProperties = positionLabel == 'off' ? {} : { barComponent: BarComponent }; - return ( - 30 ? ResponsiveBarCanvas : ResponsiveBar; + const chart = ( + { animate={false} /> ); + + return chart; }; export default NeoBarChart; diff --git a/src/chart/graph/GraphChart.tsx b/src/chart/graph/GraphChart.tsx index 87d13e7ae..89e872af6 100644 --- a/src/chart/graph/GraphChart.tsx +++ b/src/chart/graph/GraphChart.tsx @@ -12,13 +12,14 @@ import { parseNodeIconConfig } from './util/NodeUtils'; import { GraphChartVisualizationProps, layouts } from './GraphChartVisualization'; import { handleExpand } from './util/ExplorationUtils'; import { categoricalColorSchemes } from '../../config/ColorConfig'; -import { IconButton, Tooltip } from '@material-ui/core'; -import SaveAltIcon from '@material-ui/icons/SaveAlt'; -import { RenderSubValue } from '../../report/ReportRecordProcessing'; +import { IconButtonArray, IconButton } from '@neo4j-ndl/react'; +import { Tooltip } from '@mui/material'; import { downloadCSV } from '../ChartUtils'; +import { generateSafeColumnKey } from '../table/TableChart'; import { GraphChartContextMenu } from './component/GraphChartContextMenu'; import { getSettings } from '../SettingsUtils'; -import { generateSafeColumnKey } from '../table/TableChart'; +import { getPageNumbersAndNamesList } from '../../extensions/advancedcharts/Utils'; +import { CloudArrowDownIconOutline } from '@neo4j-ndl/react/icons'; /** * Draws graph data using a force-directed-graph visualization. @@ -34,7 +35,6 @@ const NeoGraphChart = (props: ChartProps) => { const settings = getSettings(props.settings, props.extensions, props.getGlobalParameter); const linkDirectionalParticles = props.settings && props.settings.relationshipParticles ? 5 : undefined; const arrowLengthProp = props?.settings?.arrowLengthProp ?? 3; - let nodePositions = props.settings && props.settings.nodePositions ? props.settings.nodePositions : {}; const parameters = props.parameters ? props.parameters : {}; @@ -123,6 +123,8 @@ const NeoGraphChart = (props: ChartProps) => { }, }); + const pageNames = getPageNumbersAndNamesList(); + const chartProps: GraphChartVisualizationProps = { data: { nodes: data.nodes, @@ -187,7 +189,7 @@ const NeoGraphChart = (props: ChartProps) => { handleExpand: handleExpand, setGlobalParameter: props.setGlobalParameter, setPageNumber: props.setPageNumber, - pageNames: [], + pageNames: pageNames, onNodeClick: (item) => handleEntityClick(item), onNodeRightClick: (item, event) => handleEntityRightClick(item, event), onRelationshipClick: (item) => handleEntityClick(item), @@ -203,7 +205,7 @@ const NeoGraphChart = (props: ChartProps) => { }, extensions: { styleRules: settings.styleRules, - actionsRules: [], + actionsRules: settings.actionsRules, }, }; @@ -213,32 +215,39 @@ const NeoGraphChart = (props: ChartProps) => { }, [props.records]); return ( -
+
- - - {settings.lockable ? : <>} - {settings.drilldownLink ? : <>} + + + + {settings.lockable ? : <>} + {settings.drilldownLink ? : <>} + {settings.allowDownload && props.records && props.records.length > 0 ? ( - - { - const rows = props.records.map((record, rownumber) => { - return Object.assign( - { id: rownumber }, - ...record._fields.map((field, i) => ({ [generateSafeColumnKey(record.keys[i])]: field })) - ); - }); - downloadCSV(rows); - }} - aria-label='download csv' - style={{ bottom: '9px', left: '3px', position: 'absolute' }} - > - - - + + + + { + const rows = props.records.map((record, rownumber) => { + return Object.assign( + { id: rownumber }, + ...record._fields.map((field, i) => ({ [generateSafeColumnKey(record.keys[i])]: field })) + ); + }); + downloadCSV(rows); + }} + /> + + + ) : ( <> )} diff --git a/src/chart/graph/GraphChartVisualization2D.tsx b/src/chart/graph/GraphChartVisualization2D.tsx index 7137470a0..a9948893b 100644 --- a/src/chart/graph/GraphChartVisualization2D.tsx +++ b/src/chart/graph/GraphChartVisualization2D.tsx @@ -1,5 +1,7 @@ import React, { useRef } from 'react'; import ForceGraph2D from 'react-force-graph-2d'; +import { actionRule } from '../../extensions/actions/ActionsRule'; +import { executeActionRule, getRuleWithFieldPropertyName } from '../../extensions/advancedcharts/Utils'; import { getTooltip } from './component/GraphChartTooltip'; import { GraphChartVisualizationProps } from './GraphChartVisualization'; import { generateNodeCanvasObject } from './util/NodeUtils'; @@ -21,7 +23,7 @@ export const NeoGraphChartVisualization2D = (props: GraphChartVisualizationProps (props.interactivity.showPropertiesOnHover ? `
${getTooltip(node)}
` : '')} nodeVal={(node: any) => node.size} onNodeClick={(item) => { - props.interactivity.onNodeClick(item); + let rules = getRuleWithFieldPropertyName(item, props.extensions.actionsRules, 'onNodeClick', 'labels'); + rules != null + ? rules.forEach((rule) => executeActionRule(rule, item, { ...props.interactivity })) + : props.interactivity.onNodeClick(item); }} onLinkClick={(item) => { - props.interactivity.onRelationshipClick(item); + let rules = getRuleWithFieldPropertyName(item, props.extensions.actionsRules, 'onLinkClick', 'type'); + rules != null + ? rules.forEach((rule) => executeActionRule(rule, item, props.interactivity.setGlobalParameter)) + : props.interactivity.onRelationshipClick(item); }} onNodeRightClick={(node, event) => props.interactivity.onNodeRightClick(node, event)} onLinkRightClick={(link, event) => props.interactivity.onRelationshipRightClick(link, event)} diff --git a/src/chart/graph/component/GraphChartContextMenu.tsx b/src/chart/graph/component/GraphChartContextMenu.tsx index a7791f7fc..56d3ad650 100644 --- a/src/chart/graph/component/GraphChartContextMenu.tsx +++ b/src/chart/graph/component/GraphChartContextMenu.tsx @@ -1,14 +1,15 @@ import * as React from 'react'; import MenuItem from '@mui/material/MenuItem'; import { GraphChartVisualizationProps } from '../GraphChartVisualization'; -import { Card, CardHeader, IconButton } from '@material-ui/core'; +import { Card, CardHeader } from '@mui/material'; +import { IconButton } from '@neo4j-ndl/react'; +import { XMarkIconOutline } from '@neo4j-ndl/react/icons'; import { NestedMenuItem, IconMenuItem } from 'mui-nested-menu'; -import CloseIcon from '@material-ui/icons/Close'; -import SearchIcon from '@material-ui/icons/Search'; +import SearchIcon from '@mui/icons-material/Search'; import { RenderNode, RenderNodeChip, RenderRelationshipChip } from '../../../report/ReportRecordProcessing'; import { getNodeLabel } from '../util/NodeUtils'; import { EditAction, EditType, GraphChartEditModal } from './GraphChartEditModal'; -import EditIcon from '@material-ui/icons/Edit'; +import EditIcon from '@mui/icons-material/Edit'; import { handleExpand, handleGetNodeRelTypes } from '../util/ExplorationUtils'; import { useEffect } from 'react'; import { mergeDatabaseStatCountsWithCountsInView } from '../util/ExplorationUtils'; @@ -37,27 +38,19 @@ export const GraphChartContextMenu = (props: GraphChartVisualizationProps) => { const menu = (
- + + } titleTypographyProps={{ variant: 'h6' }} @@ -114,38 +107,41 @@ export const GraphChartContextMenu = (props: GraphChartVisualizationProps) => { >
- - } - labelPlacement='end' - label={
Advanced settings
} + +
- {RULE_BASED_REPORT_CUSTOMIZATIONS[type] && extensions.styling ? ( - + {RULE_BASED_REPORT_CUSTOMIZATIONS[type] && extensions.styling && extensions.styling.active ? ( + { setCustomReportStyleModalOpen(true); // Open the modal. }} + clean + > + + + + ) : ( + <> + )} + {extensions.actions && extensions.actions.active && RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS[type] ? ( + + { + setCustomReportActionsModalOpen(true); // Open the modal. + }} > - + ) : ( diff --git a/src/card/settings/CardSettingsHeader.tsx b/src/card/settings/CardSettingsHeader.tsx index dacdcf20a..8ebe7a304 100644 --- a/src/card/settings/CardSettingsHeader.tsx +++ b/src/card/settings/CardSettingsHeader.tsx @@ -1,14 +1,15 @@ import React from 'react'; -import CardHeader from '@material-ui/core/CardHeader'; -import IconButton from '@material-ui/core/IconButton'; -import SaveIcon from '@material-ui/icons/Save'; -import HelpOutlineIcon from '@material-ui/icons/HelpOutline'; -import DeleteOutlineIcon from '@material-ui/icons/DeleteOutline'; -import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined'; -import FullscreenIcon from '@material-ui/icons/Fullscreen'; -import { FullscreenExit } from '@material-ui/icons'; -import DragIndicatorIcon from '@material-ui/icons/DragIndicator'; -import { Tooltip } from '@material-ui/core'; +import { Tooltip, CardHeader } from '@mui/material'; +import { IconButton } from '@neo4j-ndl/react'; +import { + ExpandIcon, + ShrinkIcon, + DragIcon, + QuestionMarkCircleIconOutline, + TrashIconOutline, + DocumentDuplicateIconOutline, + PlayCircleIconSolid, +} from '@neo4j-ndl/react/icons'; const NeoCardSettingsHeader = ({ onRemovePressed, @@ -21,52 +22,36 @@ const NeoCardSettingsHeader = ({ }) => { const maximizeButton = ( - + ); const unMaximizeButton = ( - + ); return ( - - - - +
+ + + + + + - - - + + + - - - + + +
@@ -74,15 +59,17 @@ const NeoCardSettingsHeader = ({ action={ <> {fullscreenEnabled ? expanded ? unMaximizeButton : maximizeButton : <>} - + { e.preventDefault(); onToggleCardSettings(); }} + clean + size='medium' > - + diff --git a/src/card/settings/custom/CardSettingsContentPropertySelect.tsx b/src/card/settings/custom/CardSettingsContentPropertySelect.tsx index 225f4cf35..cbb462ed8 100644 --- a/src/card/settings/custom/CardSettingsContentPropertySelect.tsx +++ b/src/card/settings/custom/CardSettingsContentPropertySelect.tsx @@ -4,10 +4,10 @@ import React, { useCallback, useContext, useEffect } from 'react'; import { RUN_QUERY_DELAY_MS } from '../../../config/ReportConfig'; import { QueryStatus, runCypherQuery } from '../../../report/ReportQueryRunner'; import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; -import { debounce, MenuItem, TextField } from '@material-ui/core'; -import { Autocomplete } from '@material-ui/lab'; +import { Autocomplete, debounce, TextField } from '@mui/material'; import NeoField from '../../../component/field/Field'; import { getReportTypes } from '../../../extensions/ExtensionUtils'; +import { Dropdown } from '@neo4j-ndl/react'; import NeoCodeEditorComponent from '../../../component/editor/CodeEditorComponent'; const NeoCardSettingsContentPropertySelect = ({ @@ -188,14 +188,17 @@ const NeoCardSettingsContentPropertySelect = ({ ` n.\`${propertyTypeDisplaySanitized}\` as display ` + `ORDER BY size(toString(value)) ASC LIMIT ${limit}`; onQueryUpdate(newQuery); - } else { + } else if (settings.type == 'Custom Query') { const newQuery = query; onQueryUpdate(newQuery); + } else { + onQueryUpdate('RETURN true;'); } } // TODO: since this component is only rendered for parameter select, this is technically not needed const parameterSelectTypes = ['Node Property', 'Relationship Property', 'Free Text', 'Custom Query', 'Date Picker']; + const selectedType = settings.type ? settings.type : 'Node Property'; const reportTypes = getReportTypes(extensions); const overridePropertyDisplayName = settings.overridePropertyDisplayName !== undefined ? settings.overridePropertyDisplayName : false; @@ -212,25 +215,21 @@ const NeoCardSettingsContentPropertySelect = ({

{reportTypes[type].helperText}

- { - handleParameterTypeUpdate(e.target.value); + selectProps={{ + onChange: (newValue) => newValue && handleParameterTypeUpdate(newValue.value), + options: parameterSelectTypes.map((option) => ({ label: option, value: option })), + value: { label: selectedType, value: selectedType }, + menuPlacement: 'auto', }} label='Selection Type' - type='text' - style={{ width: 350, marginLeft: '5px', marginTop: '0px' }} - > - {parameterSelectTypes.map((option) => ( - - {option} - - ))} - -
+ type='select' + fluid + autoFocus + style={{ marginTop: '5px' }} + /> + {settings.type == 'Free Text' || settings.type == 'Date Picker' ? ( { setLabelInputText(value); handleNodeLabelSelectionUpdate(value); @@ -302,7 +301,7 @@ const NeoCardSettingsContentPropertySelect = ({ : labelRecords.map((r) => (r._fields ? r._fields[0] : '(no data)')) } getOptionLabel={(option) => option || ''} - style={{ width: 350, marginLeft: '5px', marginTop: '5px' }} + style={{ width: 350, marginLeft: '5px', marginTop: '13px' }} inputValue={labelInputText} onInputChange={(event, value) => { setLabelInputText(value); @@ -322,6 +321,7 @@ const NeoCardSettingsContentPropertySelect = ({ ); } }} + size={'small'} value={settings.entityType ? settings.entityType : undefined} onChange={(event, newValue) => handleNodeLabelSelectionUpdate(newValue)} renderInput={(params) => ( @@ -344,7 +344,7 @@ const NeoCardSettingsContentPropertySelect = ({ : propertyRecords.map((r) => (r._fields ? r._fields[0] : '(no data)')) } getOptionLabel={(option) => (option ? option : '')} - style={{ display: 'inline-block', width: 170, marginLeft: '5px', marginTop: '5px' }} + style={{ display: 'inline-block', width: 170, marginLeft: '5px', marginTop: '13px' }} inputValue={propertyInputText} onInputChange={(event, value) => { setPropertyInputText(value); @@ -359,6 +359,7 @@ const NeoCardSettingsContentPropertySelect = ({ ); } }} + size={'small'} value={settings.propertyType} onChange={(event, newValue) => handlePropertyNameSelectionUpdate(newValue)} renderInput={(params) => ( @@ -379,7 +380,7 @@ const NeoCardSettingsContentPropertySelect = ({ : propertyRecords.map((r) => (r._fields ? r._fields[0] : '(no data)')) } getOptionLabel={(option) => (option ? option : '')} - style={{ display: 'inline-block', width: 170, marginLeft: '10px', marginTop: '5px' }} + style={{ display: 'inline-block', width: 170, marginLeft: '5px', marginTop: '13px' }} inputValue={propertyInputDisplayText} onInputChange={(event, value) => { setPropertyInputDisplayText(value); @@ -412,10 +413,11 @@ const NeoCardSettingsContentPropertySelect = ({ label='Number (optional)' disabled={!settings.propertyType} value={settings.id} - style={{ width: '170px', marginTop: '5px', marginLeft: '5px' }} + style={{ width: '170px', marginTop: '13px', marginLeft: '5px' }} onChange={(value) => { handleIdSelectionUpdate(value); }} + size={'small'} /> ) : ( diff --git a/src/card/view/CardView.tsx b/src/card/view/CardView.tsx index d02d695df..eb376111d 100644 --- a/src/card/view/CardView.tsx +++ b/src/card/view/CardView.tsx @@ -2,19 +2,22 @@ import React, { useEffect, useState } from 'react'; import { ReportItemContainer } from '../CardStyle'; import NeoCardViewHeader from './CardViewHeader'; import NeoCardViewFooter from './CardViewFooter'; -import { CardContent, IconButton } from '@material-ui/core'; +import { CardContent } from '@mui/material'; import NeoCodeEditorComponent from '../../component/editor/CodeEditorComponent'; -import PlayCircleFilledIcon from '@material-ui/icons/PlayCircleFilled'; import { CARD_FOOTER_HEIGHT, CARD_HEADER_HEIGHT } from '../../config/CardConfig'; import { extensionEnabled, getReportTypes } from '../../extensions/ExtensionUtils'; import NeoCodeViewerComponent from '../../component/editor/CodeViewerComponent'; import { NeoReportWrapper } from '../../report/ReportWrapper'; import { identifyStyleRuleParameters } from '../../extensions/styling/StyleRuleEvaluator'; -import { ThemeProvider } from '@material-ui/styles'; +import { ThemeProvider } from '@mui/material/styles'; import { lightTheme, darkHeaderTheme, luma } from '../../component/theme/Themes'; +import { IconButton } from '@neo4j-ndl/react'; +import { PlayCircleIconSolid } from '@neo4j-ndl/react/icons'; + const NeoCardView = ({ + id, title, database, query, @@ -42,18 +45,22 @@ const NeoCardView = ({ expanded, onToggleCardExpand, }) => { - const reportHeight = heightPx - CARD_FOOTER_HEIGHT - CARD_HEADER_HEIGHT + 13; - const cardHeight = heightPx - CARD_FOOTER_HEIGHT; + const reportHeight = heightPx - CARD_FOOTER_HEIGHT - CARD_HEADER_HEIGHT + 22; + const cardHeight = heightPx - CARD_FOOTER_HEIGHT + 23; const ref = React.useRef(); const [lastRunTimestamp, setLastRunTimestamp] = useState(Date.now()); + // TODO : selectorChange should handle every case where query execution needs to be re-executed + // e.g. Change of query, type, some advanced settings... + const [selectorChange, setSelectorChange] = useState(false); + const getLocalParameters = (parse_string): any => { if (!parse_string || !globalParameters) { return {}; } - let re = /(?:^|\W)\$(\w+)(?!\w)/g; + let re = /(?:^|\W|%20)\$(\w+)(?!\w)/g; let match; // If the report styling extension is enabled, extend the list of local (relevant) parameters with those used by the style rules. @@ -74,7 +81,7 @@ const NeoCardView = ({ const reportHeader = ( { + if (!settingsOpen) { + setLastRunTimestamp(Date.now()); + } + setSelectorChange(false); + }, [settingsOpen]); + + useEffect(() => { + setSelectorChange(true); + }, [query, type]); // TODO - understand why CardContent is throwing a warning based on this style config. const cardContentStyle = { @@ -151,6 +169,7 @@ const NeoCardView = ({ {active ? ( { setActive(true); }} + clean > - + {reportTypes[type] ? ( reportContent diff --git a/src/card/view/CardViewFooter.tsx b/src/card/view/CardViewFooter.tsx index 9ffd3dd39..135306180 100644 --- a/src/card/view/CardViewFooter.tsx +++ b/src/card/view/CardViewFooter.tsx @@ -1,8 +1,9 @@ import React from 'react'; -import { CardActions, Checkbox, FormControl, InputLabel, MenuItem, Select } from '@material-ui/core'; +import { CardActions, FormControl, InputLabel, MenuItem, Select } from '@mui/material'; import { categoricalColorSchemes } from '../../config/ColorConfig'; import { getReportTypes } from '../../extensions/ExtensionUtils'; import { SELECTION_TYPES } from '../../config/CardConfig'; +import { Dropdown, Label } from '@neo4j-ndl/react'; const NeoCardViewFooter = ({ fields, @@ -27,7 +28,12 @@ const NeoCardViewFooter = ({ } return ( {selectables.map((selectable, index) => { @@ -57,10 +63,8 @@ const NeoCardViewFooter = ({ ? categoricalColorSchemes[nodeColorScheme][i % totalColors] : 'lightgrey'; return ( - - - {nodeLabel} - + + {nodeLabel} + onSelectionUpdate(selectable, e.target.value)} - renderValue={(selected) => (Array.isArray(selected) ? selected.join(', ') : selected)} - value={ - selection && selection[selectable] - ? selectableFields[selectable].multiple && !Array.isArray(selection[selectable]) - ? [selection[selectable]] - : selection[selectable] - : selectableFields[selectable].multiple - ? selection[selectable] && selection[selectable].length > 0 - ? selection[selectable][0] - : [] - : '(no data)' - } - > - {/* Render choices */} - {fieldsToRender.map((field) => { - return ( - - {selectableFields[selectable].multiple && Array.isArray(selection[selectable]) ? ( - -1} /> - ) : ( - <> - )} - {field} - - ); - })} - + label={selectableFields[selectable].label} + type='select' + selectProps={{ + onChange: (newValue) => + (newValue && selectableFields[selectable].multiple + ? onSelectionUpdate( + selectable, + newValue.map((v) => v.value) + ) + : onSelectionUpdate(selectable, newValue.value)), + options: fieldsToRender.map((option) => ({ label: option, value: option })), + value: selectableFields[selectable].multiple + ? selection[selectable].map((sel) => ({ label: sel, value: sel })) + : { label: selection[selectable], value: selection[selectable] }, + isMulti: selectableFields[selectable].multiple, + isClearable: false, + menuPortalTarget: document.querySelector('body'), + }} + fluid + style={{ + minWidth: selectableFields[selectable].multiple ? 170 : 120, + marginRight: 20, + display: 'inline-block', + }} + placeholder={selectableFields[selectable].multiple ? 'Select (multiple)' : 'Select'} + > ); } diff --git a/src/card/view/CardViewHeader.tsx b/src/card/view/CardViewHeader.tsx index 1e05bc514..a412fe800 100644 --- a/src/card/view/CardViewHeader.tsx +++ b/src/card/view/CardViewHeader.tsx @@ -1,22 +1,23 @@ import React, { useEffect } from 'react'; -import CardHeader from '@material-ui/core/CardHeader'; -import IconButton from '@material-ui/core/IconButton'; -import MoreVertIcon from '@material-ui/icons/MoreVert'; -import RefreshIcon from '@material-ui/icons/Refresh'; -import FullscreenIcon from '@material-ui/icons/Fullscreen'; -import FullscreenExit from '@material-ui/icons/FullscreenExit'; -import { Badge, Dialog, DialogContent, DialogTitle, TextField } from '@material-ui/core'; +import { Badge, CardHeader, Dialog, DialogContent, DialogTitle, TextField, Tooltip } from '@mui/material'; import debounce from 'lodash/debounce'; import { useCallback } from 'react'; -import DragIndicatorIcon from '@material-ui/icons/DragIndicator'; -import { Tooltip } from '@material-ui/core'; -import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined'; -import ImageIcon from '@material-ui/icons/Image'; -import CloseIcon from '@material-ui/icons/Close'; +import { Close } from '@mui/icons-material'; import ReactMarkdown from 'react-markdown'; import gfm from 'remark-gfm'; import { replaceDashboardParameters } from '../../chart/ChartUtils'; +import { IconButton } from '@neo4j-ndl/react'; +import { + DragIcon, + EllipsisVerticalIconOutline, + ArrowPathIconOutline, + ExpandIcon, + ShrinkIcon, + CameraIconSolid, + InformationCircleIconOutline, +} from '@neo4j-ndl/react/icons'; + const NeoCardViewHeader = ({ title, description, @@ -67,10 +68,9 @@ const NeoCardViewHeader = ({
- + + +
- {neighbourRelCounts.length == 0 ? ( - - - - ) : ( - <> - )} - {neighbourRelCounts.length > 0 && - neighbourRelCounts.map((item) => { - const dir = item[1] == 'any' ? undefined : item[1] == 'out'; - return ( - - { - props.interactivity.setContextMenuOpen(false); - handleExpand(props.interactivity.selectedEntity.id, item[0], item[1], props); - setDialogOpen(false); - setCachedNeighbours(false); - }} - > - - - - - ); - })} + + {neighbourRelCounts.length == 0 ? ( + + + + ) : ( + <> + )} + {neighbourRelCounts.length > 0 && + neighbourRelCounts.map((item, index) => { + const dir = item[1] == 'any' ? undefined : item[1] == 'out'; + return ( + + { + props.interactivity.setContextMenuOpen(false); + handleExpand(props.interactivity.selectedEntity.id, item[0], item[1], props); + setDialogOpen(false); + setCachedNeighbours(false); + }} + > + + + + + ); + })} +
No relationships...
- {RenderNodeChip(props.interactivity.selectedEntity.labels, '#fff', '1px solid lightgrey')} -   - {RenderRelationshipChip(item[0], dir, '#dedede')} -   - {RenderNodeChip('...', '#fff', '1px solid lightgrey')} - {item[2]}
No relationships...
+ {RenderNodeChip(props.interactivity.selectedEntity.labels, '#fff', '1px solid lightgrey')} +   + {RenderRelationshipChip(item[0], dir, '#dedede')} +   + {RenderNodeChip('...', '#fff', '1px solid lightgrey')} + {item[2]}
@@ -157,25 +153,28 @@ export const GraphChartContextMenu = (props: GraphChartVisualizationProps) => {
- {props.data && - props.data.nodes.map((node) => ( - - { - setEditableEntityType(EditType.Relationship); - setAction(EditAction.Create); - setEditableEntity(node); - props.interactivity.setContextMenuOpen(false); - setDialogOpen(true); - }} - > - - - - - ))} + + {props.data && + props.data.nodes.map((node, index) => ( + + { + setEditableEntityType(EditType.Relationship); + setAction(EditAction.Create); + setEditableEntity(node); + props.interactivity.setContextMenuOpen(false); + setDialogOpen(true); + }} + > + + + + + ))} +
{RenderNode(node, false)} - {props.engine.selection[node.mainLabel] ? getNodeLabel(props.engine.selection, node) : ''} -
{RenderNode(node, false)} + {props.engine.selection[node.mainLabel] ? getNodeLabel(props.engine.selection, node) : ''} +
diff --git a/src/chart/graph/component/GraphChartEditModal.tsx b/src/chart/graph/component/GraphChartEditModal.tsx index eab536157..98a6234b6 100644 --- a/src/chart/graph/component/GraphChartEditModal.tsx +++ b/src/chart/graph/component/GraphChartEditModal.tsx @@ -1,16 +1,11 @@ import { GraphChartVisualizationProps } from '../GraphChartVisualization'; import React, { useEffect } from 'react'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import Button from '@mui/material/Button'; -import { Badge, IconButton } from '@material-ui/core'; -import { Fab, TextField, Typography } from '@material-ui/core'; -import AddIcon from '@material-ui/icons/Add'; -import { Autocomplete } from '@material-ui/lab'; -import CloseIcon from '@material-ui/icons/Close'; -import PlayArrow from '@material-ui/icons/PlayArrow'; +import { Dialog, DialogContent, DialogContentText, DialogTitle } from '@mui/material'; +import { Badge, Button, IconButton } from '@mui/material'; +import { Fab, TextField, Typography } from '@mui/material'; +import AddIcon from '@mui/icons-material/Add'; +import CloseIcon from '@mui/icons-material/Close'; +import PlayArrow from '@mui/icons-material/PlayArrow'; import { LabelTypeAutocomplete } from './autocomplete/LabelTypeAutocomplete'; import { DeletePropertyButton } from './button/modal/DeletePropertyButton'; import { @@ -132,16 +127,16 @@ export const GraphChartEditModal = (props: GraphChartEditorVisualizationProps) =

Properties

- {properties.map((property, index) => { - const disabled = !( - typeof property.value == 'string' || - typeof property.value == 'number' || - property.value.toNumber !== undefined - ); + + {properties.map((property, index) => { + const disabled = !( + typeof property.value == 'string' || + typeof property.value == 'number' || + property.value.toNumber !== undefined + ); - return ( - <> - + return ( + @@ -160,6 +155,7 @@ export const GraphChartEditModal = (props: GraphChartEditorVisualizationProps) = - - ); - })} + ); + })} - - - + + + +
{index + 1}. { setProperties([...properties.slice(0, index), ...properties.slice(index + 1)]); setPropertyInputTexts([ @@ -184,30 +181,32 @@ export const GraphChartEditModal = (props: GraphChartEditorVisualizationProps) = />
- - { - const newProperty = { name: '', value: '' }; - setProperties(properties.concat(newProperty)); - }} - > - - - -
+ + { + const newProperty = { name: '', value: '' }; + setProperties(properties.concat(newProperty)); + }} + > + + + +

+
+ +
+ + + + + + + + + + + + + +
+
+ {e.label} + {e.enabled && e.author == 'Neo4j Professional Services' && ( + + )} +
+
+ + { + let active = extensions[e.name] == undefined ? true : undefined; + if (e.enabled) { + setExtensionEnabled(e.name, active); + + // Subscribing the reducer binded to the newly enabled extension + // to the extensionReducer + if (e.reducerPrefix) { + setExtensionReducerEnabled(e.reducerPrefix, active); + } + } else { + onExtensionUnavailableTriggered(e.label); + // If an extension presents a reducer, we need to unbind it from the extension reducer + if (e.reducerPrefix) { + setExtensionReducerEnabled(e.reducerPrefix, active); + } + } + }} + /> + +
+
+

{e.description}

+
+

+ Author:{' '} + + {e.author} + +

+
+
+ +
+
+
+
); })} - -
+
+ ) : ( <> @@ -143,13 +153,14 @@ const mapStateToProps = (state) => ({ const mapDispatchToProps = (dispatch) => ({ setExtensionEnabled: (name, enabled) => dispatch(setExtensionEnabled(name, enabled)), + setExtensionReducerEnabled: (name, enabled) => dispatch(setExtensionReducerEnabled(name, enabled)), onExtensionUnavailableTriggered: (name) => dispatch( createNotificationThunk( `Extension '${name}' Unavailable`, // eslint-disable-next-line no-multi-str - 'This extension is not available in the open-source version of NeoDash.\n \ - To learn more about professional extensions, check out the project documentation.' + 'This extension is not available in this version of NeoDash.\n \ + To learn more about expert extensions, check out the project documentation.' ) ), }); diff --git a/src/extensions/ExtensionsReducer.ts b/src/extensions/ExtensionsReducer.ts deleted file mode 100644 index de715f429..000000000 --- a/src/extensions/ExtensionsReducer.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Reducers define changes to the application state when a given action is performed. - */ - -export const initialState = {}; - -const update = (state, mutations) => Object.assign({}, state, mutations); - -export const extensionsReducer = (state = initialState, action: { type: any; payload: any }) => { - const { type, payload } = action; - - if (!action.type.startsWith('DASHBOARD/EXTENSIONS')) { - return state; - } - - switch (type) { - default: { - return state; - } - } -}; diff --git a/src/extensions/actions/ActionsRuleCreationModal.tsx b/src/extensions/actions/ActionsRuleCreationModal.tsx new file mode 100644 index 000000000..d2d4e57d7 --- /dev/null +++ b/src/extensions/actions/ActionsRuleCreationModal.tsx @@ -0,0 +1,463 @@ +import React, { useEffect } from 'react'; +import CloseIcon from '@mui/icons-material/Close'; +import AddIcon from '@mui/icons-material/Add'; +import StarsIcon from '@mui/icons-material/Stars'; +import { + AdjustmentsHorizontalIconOutline, + XMarkIconOutline, + PlusIconOutline, + PlayIconSolid, + SparklesIconOutline, +} from '@neo4j-ndl/react/icons'; +import { getPageNumbersAndNamesList } from '../advancedcharts/Utils'; +import { IconButton, Button, Dialog, Dropdown, TextInput } from '@neo4j-ndl/react'; +import { Autocomplete, TextField } from '@mui/material'; + +// The set of conditional checks that are included in the rule specification. +const RULE_CONDITIONS = { + table: [ + { + value: 'Click', + label: 'Cell Click', + default: true, + }, + { + value: 'doubleClick', + label: 'Cell Double Click', + }, + ], + map: [ + { + value: 'Click', + label: 'Click on Tooltip', + default: true, + }, + ], + graph: [ + { + value: 'onNodeClick', + label: 'Node Click', + default: true, + }, + { + value: 'onLinkClick', + label: 'Link Click', + }, + ], +}; + +// For each report type, the customizations that can be specified using rules. +export const RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS = { + table: [ + { + value: 'set variable', + label: 'Parameter', + }, + { + value: 'set page', + label: 'Page', + }, + ], + map: [ + { + value: 'set variable', + label: 'Parameter', + }, + { + value: 'set page', + label: 'Page', + }, + ], + graph: [ + { + value: 'set variable', + label: 'Parameter', + }, + { + value: 'set page', + label: 'Page', + }, + ], +}; + +// Get the default rule structure to append when a rule gets added to the list. +const getDefaultRule = (type) => { + let rule = RULE_CONDITIONS[type].filter((e) => e.default !== undefined && e.default); + rule = rule.length > 0 ? rule[0] : RULE_CONDITIONS[type][0]; + let customization = RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS[type].filter( + (e) => e.default !== undefined && e.default + ); + customization = customization.length > 0 ? customization[0] : RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS[type][0]; + return { + condition: rule.value, + field: '', + value: '', + customization: customization.value, + customizationValue: '', + }; +}; + +/** + * The pop-up window used to build and specify custom styling rules for reports. + */ +export const NeoCustomReportActionsModal = ({ + customReportActionsModalOpen, + settingName, + settingValue, + type, + fields, + setCustomReportActionsModalOpen, + onReportSettingUpdate, +}) => { + // The rule set defined in this modal is updated whenever the setting value is externally changed. + const [rules, setRules] = React.useState([]); + useEffect(() => { + if (settingValue) { + setRules(settingValue); + } + }, [settingValue]); + + const pageNames = getPageNumbersAndNamesList(); + const handleClose = () => { + // If no rules are specified, clear the special report setting that holds the customization rules. + if (rules.length == 0) { + onReportSettingUpdate(settingName, undefined); + } else { + onReportSettingUpdate(settingName, rules); + } + setCustomReportActionsModalOpen(false); + }; + + // Update a single field in one of the rules in the rule array. + const updateRuleField = (ruleIndex, ruleField, ruleFieldValue) => { + let newRules = [...rules]; // Deep copy + newRules[ruleIndex][ruleField] = ruleFieldValue; + setRules(newRules); + }; + + /** + * Create the list of suggestions used in the autocomplete box of the rule specification window. + * This will be dynamic based on the type of report we are customizing. + */ + const createFieldVariableSuggestions = (c, labels, labelRel) => { + if (!fields) { + return []; + } + if (type == 'graph' || type == 'map') { + return fields + .map((node, index) => { + if (!Array.isArray(node)) { + return undefined; + } + return fields[index].map((property, propertyIndex) => { + if (!['Click', 'onNodeClick'].includes(c)) { + return undefined; + } + + if (labels) { + if (propertyIndex > 0) { + return undefined; + } + return fields[index][0]; + } + + if (propertyIndex == 0) { + return undefined; + } + + return `${fields[index][0]}.${property}`; + }); + }) + .flat() + .filter((e) => e !== undefined) + .filter((e) => labelRel == null || e.startsWith(labelRel)); + } + if (type == 'bar' || type == 'line' || type == 'pie' || type == 'table' || type == 'value') { + return fields; + } + return []; + }; + + const createFieldVariableSuggestionsFromRule = (rule, type) => { + let suggestions; + if (type) { + suggestions = createFieldVariableSuggestions(rule.condition, true, null).filter((e) => + e.toLowerCase().startsWith(rule.field.toLowerCase()) + ); + } else if (rule.customization == 'set page' && pageNames) { + suggestions = pageNames; + } else { + suggestions = createFieldVariableSuggestions(rule.condition, false, rule.field).filter((e) => + e.toLowerCase().startsWith(rule.value.toLowerCase()) + ); + } + + // When we are accessing node properties (not page names), parse the node label + property pair to only show properties. + if (rule.customization !== 'set page') { + suggestions = suggestions.map((e) => e.split('.')[1] || e); + } + + return suggestions; + }; + + const getActionHelper = (rule, index, customization) => { + if (customization == 'set variable') { + return ( + <> + + + + + updateRuleField(index, 'customizationValue', e.target.value)} + > + + + ); + } else if (customization == 'set page') { + return ( + <> + + + + + ); + } + return undefined; + }; + + return ( +
+ {customReportActionsModalOpen ? ( + + + + Report Actions + + +

You can define actions for the report here.

+

+ Report actions enable you to create conditional logic in the dashboard, for example, setting a parameter + dynamically based on a 'node click' or 'table click'. +

+

For more on report actions, see the documentation.

+
+
+ + + {rules.map((rule, index) => { + const ruleType = RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS[type].find( + (el) => el.value === rule.customization + ); + const ruleTrigger = RULE_CONDITIONS[type].find((el) => el.value === rule.condition); + return ( + <> + + + + + + + + + + {getActionHelper(rule, index, rules[index].customization)} + + + + + + + + + +
+ + + ); + })} + + + + +
+ {index + 1}. + + ON + +
+
+ updateRuleField(index, 'condition', newValue.value), + options: + RULE_CONDITIONS[type] && + RULE_CONDITIONS[type].map((option) => ({ + label: option.label, + value: option.value, + })), + value: { label: ruleTrigger ? ruleTrigger.label : '', value: rule.condition }, + }} + > + + } + style={{ width: 150, padding: 0 }} + onInputChange={(event, value) => { + updateRuleField(index, 'field', value); + }} + onChange={(event, newValue) => { + updateRuleField(index, 'field', newValue); + }} + renderInput={(params) => ( + + )} + /> + + SET + +
+
+ updateRuleField(index, 'customization', newValue.value), + options: + RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS[type] && + RULE_BASED_REPORT_ACTIONS_CUSTOMIZATIONS[type].map((option) => ({ + label: option.label, + value: option.value, + })), + value: { label: ruleType ? ruleType.label : '', value: rule.customization }, + }} + > + + TO + +
+
+ } + style={{ display: 'inline-block', width: 185, marginLeft: '5px', marginTop: '5px' }} + onInputChange={(event, value) => { + updateRuleField(index, 'value', value); + }} + onChange={(event, newValue) => { + updateRuleField(index, 'value', newValue); + }} + renderInput={(params) => ( + + )} + /> + + { + setRules([...rules.slice(0, index), ...rules.slice(index + 1)]); + }} + > + + +
+
+ { + const newRule = getDefaultRule(type); + setRules(rules.concat(newRule)); + }} + > + + +
+
+
+ + +
+
+ ) : ( + <> + )} +
+ ); +}; + +export default NeoCustomReportActionsModal; diff --git a/src/extensions/advancedcharts/Utils.ts b/src/extensions/advancedcharts/Utils.ts index acdb12f4d..3b667fcb4 100644 --- a/src/extensions/advancedcharts/Utils.ts +++ b/src/extensions/advancedcharts/Utils.ts @@ -24,6 +24,74 @@ const ruleFieldCheck = (ruleValue, value) => { return value.trim() == ruleValue.trim(); }; +/** + * Returns a list of pairs, where each pair represents a page number and a name. + */ +export const getPageNumbersAndNamesList = () => { + return useSelector(getPageNumbersAndNames); +}; + +/** + * Get the relevant page for a specific action rule. + */ +export const getPageFromPageNames = (pageNames, ruleValue) => { + // TODO - handle renames and reorders automatically by updating the action logic. + let page = pageNames.filter((pageNew) => pageNew.split('/')[1] == ruleValue.split('/')[1]); + if (page.length == 1) { + return page[0]; + } + page = pageNames.filter((pageNew) => pageNew == ruleValue); + if (page.length == 1) { + return page[0]; + } + return null; +}; + +/** + * + * @param rule - an action rule as specified by the user {"condition", "field", "value", "customization", "customizationValue"} + * @param e - element to execute the rule on. + * @param props - ReportProps object to get callback from to update the state. + * @param type - type of rule, currently unused. + */ +export const executeActionRule = (rule, e, props, _type = 'default') => { + if (rule !== null) { + if (rule.customization == 'set variable' && props && props.setGlobalParameter) { + // call thunk for $neodash_customizationValue + let rValue = rule.value == 'id' ? 'id ' : rule.value; + if (rValue != '' && e.row && e.row[rValue]) { + props.setGlobalParameter(`neodash_${rule.customizationValue}`, e.row[rule.value]); + } else if (rule.value != '' && e.properties && e.properties[rule.value]) { + props.setGlobalParameter(`neodash_${rule.customizationValue}`, e.properties[rule.value]); + } else { + props.setGlobalParameter(`neodash_${rule.customizationValue}`, e.value); + } + } else if (rule.customization == 'set page' && props.setPageNumber && props.pageNames) { + let page = getPageFromPageNames(props.pageNames, rule.value); + if (page) { + props.setPageNumber(page.split('/')[0]); + } else { + props.setPageNumber(undefined); + } + } + } +}; + +/** + * Evaluates and runs actions based on an element based on the rule set defined in the settings. + * @param e - the element. + * @param actionsRules - the list of rules. + * @param props - ChartProps object with callbacks to execute rule. + * @param action - the type of action to perform. + * @param type - the rule type. + */ +export const performActionOnElement = (e, actionsRules, props, action, type = 'default') => { + let rules = getRule(e, actionsRules, action); + if (rules !== null) { + rules.forEach((rule) => executeActionRule(rule, e, props, type)); + } +}; + export const unassign = (target, source) => { Object.keys(source).forEach((key) => { delete target[key]; diff --git a/src/extensions/advancedcharts/chart/areamap/AreaMapChart.tsx b/src/extensions/advancedcharts/chart/areamap/AreaMapChart.tsx index 1ebdc370c..a75db223a 100644 --- a/src/extensions/advancedcharts/chart/areamap/AreaMapChart.tsx +++ b/src/extensions/advancedcharts/chart/areamap/AreaMapChart.tsx @@ -32,6 +32,7 @@ function createGeoDictionary(records, selection) { }); return data; } + /** * To speed up the binding process, let's reduce the list into a object to use the index access * @param features @@ -48,6 +49,7 @@ function fromFeatureListToObject(features, desiredLevel) { }); return res; } + /** * Renders Neo4j Records inside a GeoJSON map. */ @@ -57,11 +59,15 @@ const NeoAreaMapChart = (props: ChartProps) => { const { selection } = props; const dimensions = props.dimensions ? props.dimensions : { width: 100, height: 100 }; const keyLength = props.settings && props.settings.countryCodeFormat ? props.settings.countryCodeFormat : 'Alpha-2'; + + // Key used to refresh the visualization let key = `${dimensions.width},${dimensions.height},${props.fullscreen}`; const [data, setData] = useState({}); - // Two feature levels (ideally we can even more) + + // Two feature levels (ideally we can extend this too) const [featureLevel0, setFeatureLevel0] = useState({}); const [featureLevel1, setFeatureLevel1] = useState({}); + const [isReady, setIsReady] = useState(false); const mapProviderURL = props.settings && props.settings.providerUrl diff --git a/src/extensions/advancedcharts/chart/areamap/PolygonLayer.tsx b/src/extensions/advancedcharts/chart/areamap/PolygonLayer.tsx index 18bc0dfd6..d97479ed7 100644 --- a/src/extensions/advancedcharts/chart/areamap/PolygonLayer.tsx +++ b/src/extensions/advancedcharts/chart/areamap/PolygonLayer.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { useMap, GeoJSON } from 'react-leaflet'; import 'leaflet/dist/leaflet.css'; -import Button from '@material-ui/core/Button'; +import { Button } from '@mui/material'; import './styles/PolygonStyle.css'; import { categoricalColorSchemes } from '../../../../config/ColorConfig'; import { abbreviateNumber } from '../../../../chart/map/MapUtils'; diff --git a/src/extensions/advancedcharts/chart/circlepacking/CirclePackingChart.tsx b/src/extensions/advancedcharts/chart/circlepacking/CirclePackingChart.tsx index 977c589b2..685e72903 100644 --- a/src/extensions/advancedcharts/chart/circlepacking/CirclePackingChart.tsx +++ b/src/extensions/advancedcharts/chart/circlepacking/CirclePackingChart.tsx @@ -1,18 +1,15 @@ import React, { useEffect } from 'react'; import { ResponsiveCirclePacking } from '@nivo/circle-packing'; import { useState } from 'react'; -import { Tooltip } from '@material-ui/core'; -import RefreshIcon from '@material-ui/icons/Refresh'; +import { Tooltip } from '@mui/material'; +import Refresh from '@mui/icons-material/Refresh'; import { ChartProps } from '../../../../chart/Chart'; import { NoDrawableDataErrorMessage } from '../../../../component/editor/CodeViewerComponent'; -import { - checkResultKeys, - mutateName, - processHierarchyFromRecords, - findObject, - flatten, -} from '../../../../chart/ChartUtils'; +import { mutateName, processHierarchyFromRecords, findObject, flatten } from '../../../../chart/ChartUtils'; +/** + * Embeds a CirclePackaging (from Charts) into NeoDash. + */ const NeoCirclePackingChart = (props: ChartProps) => { if (props.records == null || props.records.length == 0 || props.records[0].keys == null) { return <>No data, re-run the report.; @@ -20,22 +17,26 @@ const NeoCirclePackingChart = (props: ChartProps) => { const { records } = props; const { selection } = props; const [data, setData] = useState(undefined); - useEffect(() => { - setData(commonProperties.data); - }, [props.selection]); + const [commonProperties, setCommonProperties] = useState({ data: { name: 'Total', children: [] } }); const [refreshable, setRefreshable] = useState(false); if (!selection || props.records == null || props.records.length == 0 || props.records[0].keys == null) { return ; } - const dataPre = processHierarchyFromRecords(records, selection); - dataPre.forEach((currentNode) => mutateName(currentNode)); + useEffect(() => { + let dataPre = processHierarchyFromRecords(records, selection); + dataPre.forEach((currentNode) => mutateName(currentNode)); + setCommonProperties({ data: dataPre.length == 1 ? dataPre[0] : { name: 'Total', children: dataPre } }); + }, [records]); + + useEffect(() => { + setData(commonProperties.data); + }, [props.selection, commonProperties]); // Where a user give us the hierarchy with a common root, in that case we can push the entire tree. // Where a user give us just the tree starting one hop away from the root. // as Nivo needs a common root, so in that case, we create it for them. - const commonProperties = { data: dataPre.length == 1 ? dataPre[0] : { name: 'Total', children: dataPre } }; if (data == undefined) { setData(commonProperties.data); } @@ -68,12 +69,13 @@ const NeoCirclePackingChart = (props: ChartProps) => { <>
{refreshable ? ( - - + { setData(commonProperties.data); setRefreshable(false); }} + className='n-z-10' style={{ fontSize: '1.3rem', opacity: 0.6, @@ -81,12 +83,11 @@ const NeoCirclePackingChart = (props: ChartProps) => { right: 12, position: 'absolute', borderRadius: '12px', - zIndex: 5, background: '#eee', }} color='disabled' fontSize='small' - > + > ) : (
diff --git a/src/extensions/advancedcharts/chart/sankey/SankeyChart.tsx b/src/extensions/advancedcharts/chart/sankey/SankeyChart.tsx index 747ac3718..9e9cbfcf5 100644 --- a/src/extensions/advancedcharts/chart/sankey/SankeyChart.tsx +++ b/src/extensions/advancedcharts/chart/sankey/SankeyChart.tsx @@ -47,7 +47,7 @@ const NeoSankeyChart = (props: ChartProps) => { useEffect(() => { buildVisualizationDictionaryFromRecords(props.records); - }, []); + }, [props.records]); if (props.records == null || props.records.length == 0 || props.records[0].keys == null) { return <>No data, re-run the report.; diff --git a/src/extensions/advancedcharts/chart/sunburst/SunburstChart.tsx b/src/extensions/advancedcharts/chart/sunburst/SunburstChart.tsx index 7643356a3..aac6d5334 100644 --- a/src/extensions/advancedcharts/chart/sunburst/SunburstChart.tsx +++ b/src/extensions/advancedcharts/chart/sunburst/SunburstChart.tsx @@ -1,14 +1,14 @@ import React, { useState, useEffect } from 'react'; import { - checkResultKeys, mutateName as mutateHierarchyNameIntoDisplayName, processHierarchyFromRecords, findObject, flatten, + mutateName, } from '../../../../chart/ChartUtils'; import { ResponsiveSunburst } from '@nivo/sunburst'; -import { Tooltip } from '@material-ui/core'; -import RefreshIcon from '@material-ui/icons/Refresh'; +import { Tooltip } from '@mui/material'; +import { Refresh } from '@mui/icons-material'; import { ChartProps } from '../../../../chart/Chart'; import { NoDrawableDataErrorMessage } from '../../../../component/editor/CodeViewerComponent'; /** @@ -20,31 +20,31 @@ const NeoSunburstChart = (props: ChartProps) => { } const { records } = props; const { selection } = props; - useEffect(() => { - setData(commonProperties.data); - }, [props.selection]); - + const [data, setData] = useState(undefined); + const [commonProperties, setCommonProperties] = useState({ data: { name: 'Total', children: [] } }); const [refreshable, setRefreshable] = useState(false); if (!selection || props.records == null || props.records.length == 0 || props.records[0].keys == null) { return ; } - const dataPre = processHierarchyFromRecords(records, selection); - dataPre.forEach((currentNode) => mutateHierarchyNameIntoDisplayName(currentNode)); + useEffect(() => { + let dataPre = processHierarchyFromRecords(records, selection); + dataPre.forEach((currentNode) => mutateName(currentNode)); + setCommonProperties({ data: dataPre.length == 1 ? dataPre[0] : { name: 'Total', children: dataPre } }); + }, [records]); + + useEffect(() => { + setData(commonProperties.data); + }, [props.selection, commonProperties]); // Where a user give us the hierarchy with a common root, in that case we can push the entire tree. // Where a user give us just the tree starting one hop away from the root. // as Nivo needs a common root, so in that case, we create it for them. - const commonProperties = { data: dataPre.length == 1 ? dataPre[0] : { name: 'Total', children: dataPre } }; - - const [data, setData] = useState(commonProperties.data); - if (data == undefined) { setData(commonProperties.data); } - const [back, setBack] = useState(false); const settings = props.settings ? props.settings : {}; const legendHeight = 20; const marginRight = settings.marginRight ? settings.marginRight : 24; @@ -67,12 +67,13 @@ const NeoSunburstChart = (props: ChartProps) => { <>
{refreshable ? ( - - + { setData(commonProperties.data); setRefreshable(false); }} + className='n-z-10' style={{ fontSize: '1.3rem', opacity: 0.6, @@ -80,12 +81,11 @@ const NeoSunburstChart = (props: ChartProps) => { right: 12, position: 'absolute', borderRadius: '12px', - zIndex: 5, background: '#eee', }} color='disabled' fontSize='small' - > + > ) : (
diff --git a/src/extensions/advancedcharts/chart/treemap/TreeMapChart.tsx b/src/extensions/advancedcharts/chart/treemap/TreeMapChart.tsx index 19883c9f0..03b0d3acf 100644 --- a/src/extensions/advancedcharts/chart/treemap/TreeMapChart.tsx +++ b/src/extensions/advancedcharts/chart/treemap/TreeMapChart.tsx @@ -1,15 +1,9 @@ import React, { useEffect } from 'react'; import { ResponsiveTreeMap } from '@nivo/treemap'; -import { - checkResultKeys, - mutateName, - processHierarchyFromRecords, - findObject, - flatten, -} from '../../../../chart/ChartUtils'; +import { mutateName, processHierarchyFromRecords, findObject, flatten } from '../../../../chart/ChartUtils'; import { useState } from 'react'; -import { Tooltip } from '@material-ui/core'; -import RefreshIcon from '@material-ui/icons/Refresh'; +import { Tooltip } from '@mui/material'; +import { Refresh } from '@mui/icons-material'; import { ChartProps } from '../../../../chart/Chart'; import { NoDrawableDataErrorMessage } from '../../../../component/editor/CodeViewerComponent'; @@ -23,22 +17,26 @@ const NeoTreeMapChart = (props: ChartProps) => { const { records } = props; const { selection } = props; const [data, setData] = useState(undefined); - useEffect(() => { - setData(commonProperties.data); - }, [props.selection]); + const [commonProperties, setCommonProperties] = useState({ data: { name: 'Total', children: [] } }); const [refreshable, setRefreshable] = useState(false); if (!selection || props.records == null || props.records.length == 0 || props.records[0].keys == null) { return ; } - const dataPre = processHierarchyFromRecords(records, selection); - dataPre.forEach((currentNode) => mutateName(currentNode)); + useEffect(() => { + let dataPre = processHierarchyFromRecords(records, selection); + dataPre.forEach((currentNode) => mutateName(currentNode)); + setCommonProperties({ data: dataPre.length == 1 ? dataPre[0] : { name: 'Total', children: dataPre } }); + }, [records]); + + useEffect(() => { + setData(commonProperties.data); + }, [props.selection, commonProperties]); // Where a user give us the hierarchy with a common root, in that case we can push the entire tree. // Where a user give us just the tree starting one hop away from the root. // as Nivo needs a common root, so in that case, we create it for them. - const commonProperties = { data: dataPre.length == 1 ? dataPre[0] : { name: 'Total', children: dataPre } }; if (data == undefined) { setData(commonProperties.data); } @@ -71,12 +69,13 @@ const NeoTreeMapChart = (props: ChartProps) => { <>
{refreshable ? ( - - + { setData(commonProperties.data); setRefreshable(false); }} + className='n-z-10' style={{ fontSize: '1.3rem', opacity: 0.6, @@ -84,12 +83,11 @@ const NeoTreeMapChart = (props: ChartProps) => { right: 12, position: 'absolute', borderRadius: '12px', - zIndex: 5, background: '#eee', }} color='disabled' fontSize='small' - > + > ) : (
diff --git a/src/extensions/query-translator/QueryTranslatorConfig.ts b/src/extensions/query-translator/QueryTranslatorConfig.ts new file mode 100644 index 000000000..b3cd62456 --- /dev/null +++ b/src/extensions/query-translator/QueryTranslatorConfig.ts @@ -0,0 +1,113 @@ +import { SELECTION_TYPES } from '../../config/CardConfig'; +import { ModelClient } from './clients/ModelClient'; +import { OpenAiClient } from './clients/OpenAi/OpenAiClient'; + +// TODO: implement VertexAiClient +import { VertexAiClient } from './clients/VertexAiClient'; + +interface ClientSettingEntry { + label: string; + type: SELECTION_TYPES; + default: any; + authentication?: boolean; // Required for authentication, the user should insert all the required fields before trying to authenticate + hasAuthButton?: boolean; // Append a button at the end of the selector to trigger an auth request. + methodFromClient?: string; // String that contains the name of the client function to call to retrieve the data needed to fill the option +} + +interface ClientSettings { + apiKey: ClientSettingEntry; + modelType: ClientSettingEntry; + region?: ClientSettingEntry; +} + +interface ClientConfig { + clientName: string; + clientClass: ModelClient; + clientSettingsModal: JSX.Element; + settings: ClientSettings; +} + +interface AvailableClients { + OpenAI: ClientConfig; + vertexAi: ClientConfig; +} + +interface QueryTranslatorConfig { + availableClients: AvailableClients; +} + +export const QUERY_TRANSLATOR_CONFIG: QueryTranslatorConfig = { + availableClients: { + OpenAI: { + clientName: 'OpenAI', + clientClass: OpenAiClient, + settings: { + apiKey: { + label: 'OpenAI API Key', + type: SELECTION_TYPES.TEXT, + default: '', + hasAuthButton: true, + authentication: true, + }, + modelType: { + label: 'Model', + type: SELECTION_TYPES.LIST, + methodFromClient: 'getListModels', + default: '', + authentication: false, + }, + }, + }, + // vertexAi: { + // clientName: "vertexAi", + // clientClass: VertexAiClient, + // settings: { + // apiKey: { + // label: 'Api Key to authenticate the client', + // type: SELECTION_TYPES.TEXT, + // default: '', + // }, + // modelType: { + // label: 'Select from the possible model types', + // type: SELECTION_TYPES.LIST, + // needsStateValues: true, + // default: "Insert your Api Key first", + // }, + // region: { + // label: 'GCP Region', + // type: SELECTION_TYPES.LIST, + // needsStateValues: true, + // default: [], + // } + // } + // }, + }, +}; + +/** + * Function to get the extension config + * @param extensionName Name of the desired extension + * @returns Predefined fields of configuration for an extension + */ +export function getQueryTranslatorDefaultConfig(providerName) { + return QUERY_TRANSLATOR_CONFIG.availableClients && + QUERY_TRANSLATOR_CONFIG.availableClients[providerName] && + QUERY_TRANSLATOR_CONFIG.availableClients[providerName].settings + ? QUERY_TRANSLATOR_CONFIG.availableClients[providerName].settings + : {}; +} + +/** + * Given the provider and the settings in input, return the related client object + * @param modelProvider Name of the provider (for example: OpenAi) + * @param settings Dictionary that will be unpacked by the client itself + * @returns Client object related to the provider + */ +export function getModelClientObject(modelProvider, settings) { + let providerDetails = QUERY_TRANSLATOR_CONFIG.availableClients[modelProvider]; + if (providerDetails === undefined) { + throw Error(`Invalid provider name${modelProvider}`); + } + let modelProviderClass = providerDetails.clientClass; + return new modelProviderClass(settings); +} diff --git a/src/extensions/query-translator/clients/ModelClient.ts b/src/extensions/query-translator/clients/ModelClient.ts new file mode 100644 index 000000000..77cfed716 --- /dev/null +++ b/src/extensions/query-translator/clients/ModelClient.ts @@ -0,0 +1,210 @@ +import { MAX_NUM_VALIDATION, nodePropsQuery, relPropsQuery, relQuery, TASK_DEFINITION } from './const'; + +const notImplementedError = (functionName) => { + throw new Error(`Not Implemented: ${functionName}`); +}; +const consoleLogAsync = async (message: string, other?: any) => { + await new Promise((resolve) => setTimeout(resolve, 0)).then(() => console.info(message, other)); +}; + +// A model client should just handle the communication +export abstract class ModelClient { + apiKey: string; + + modelType: string | undefined; + + listAvailableModels: string[]; + + createSystemMessage: any; + + modelClient: any; + + driver: any; + + constructor(settings) { + this.apiKey = settings.apiKey; + this.modelType = settings.modelType; + this.listAvailableModels = []; + this.setModelClient(); + } + + setModelClient() { + notImplementedError('setModelClient'); + } + + /** + * Function to query the db directly from the client + * @param query Query to run + * @param database Selected database + * @returns The records results if the query runs correctly, otherwise the function will throw an error + */ + async queryDatabase(query, database) { + if (this.driver) { + const session = this.driver.session({ database: database }); + const transaction = session.beginTransaction({ timeout: 20 * 1000, connectionTimeout: 2000 }); + + let res = await transaction + .run(query, undefined) + .then((res) => { + const { records } = res; + let elems = records.map((elem) => { + return elem.toObject()[elem.keys[0]]; + }); + records.length > 0 ?? elems.unshift(records[0].keys); + transaction.commit(); + return elems; + }) + .catch(async (e) => { + throw e; + }); + return res; + } + throw new Error('Driver not present'); + } + + createSchemaText(nodeProps, relProps, rels) { + return ` + This is the schema representation of the Neo4j database. + Node properties are the following: + ${JSON.stringify(nodeProps)} + Relationship properties are the following: + ${JSON.stringify(relProps)} + Relationship point from source to target nodes + ${JSON.stringify(rels)} + Make sure to respect relationship types and directions + `; + } + + async generateSchema(database) { + try { + let nodeProps = await this.queryDatabase(nodePropsQuery, database); + let relProps = await this.queryDatabase(relPropsQuery, database); + let rels = await this.queryDatabase(relQuery, database); + return this.createSchemaText(nodeProps, relProps, rels); + } catch (e) { + throw Error(`Couldn't generate schema due to: ${e.message}`); + } + } + + getSystemMessage(schemaText) { + return `${TASK_DEFINITION} + Schema: + ${schemaText} + `; + } + + setDriver(driver: any) { + this.driver = driver; + } + + getMessageContent(_message: any) { + notImplementedError('getMessageContent'); + return ''; + } + + /** + * Method responsible to ask the model to translate the message. + * @param inputMessage + * @param history History of messages exchanged between a card and the model client + * @param database Databased used from the report, it will be used to fetch the schema + * @param reportType Type of report asking that requires the translation + * @param setValidationStep Function to set the current validation step outside the function + * @returns The new history to assign to the card. If there was no possibility of validating the query, the + * method will return the same history passed in input + */ + async queryTranslation( + inputMessage, + history, + database, + reportType, + onRetry = (value) => { + let x = value; + } + ) { + // Creating a copy of the history + let newHistory = [...history]; + // Creating a tmp history to prevent updating the history with erroneous messages + let tmpHistory = [...newHistory]; + let schema = ''; + let query = ''; + try { + // If empty, the first message will be the task definition + if (tmpHistory.length == 0) { + schema = await this.generateSchema(database); + tmpHistory.push(this.addSystemMessage(this.getSystemMessage(schema))); + } + tmpHistory.push(this.addUserMessage(inputMessage, reportType)); + + let retries = 0; + let isValidated = false; + let errorMessage = ''; + + // While is not validated and we didn't exceed the maximum retry number + while (!isValidated && retries < MAX_NUM_VALIDATION) { + retries += 1; + onRetry(retries); + + // Get the answer to the question + let modelAnswer = await this.chatCompletion(tmpHistory); + tmpHistory.push(modelAnswer); + + // and try to validate it + let validationResult = await this.validateQuery(modelAnswer, database); + isValidated = validationResult[0]; + errorMessage = validationResult[1]; + + // If you can't validate the query, send the model a message to try to fix it + if (!isValidated) { + tmpHistory.push(this.addErrorMessage(errorMessage)); + } else { + if (newHistory.length == 0 && schema) { + newHistory.push(this.addSystemMessage(this.getSystemMessage(schema))); + } + newHistory.push(this.addUserMessage(inputMessage, reportType, true)); + newHistory.push(modelAnswer); + query = this.getMessageContent(modelAnswer); + } + } + if (!isValidated) { + throw Error( + `The model could not translate your question to valid Cypher: '${inputMessage}'. Try writing a more descriptive question, explicitly calling out the node labels, relationship types, and property names.` + ); + } + } catch (error) { + await consoleLogAsync('Error during query', error); + throw error; + } + return [query, newHistory]; + } + + async validateQuery(_message, _database) { + notImplementedError('validateQuery'); + } + + async chatCompletion(_history) { + notImplementedError('chatCompletion'); + } + + addUserMessage(_content, _reportType, _plain = false) { + notImplementedError('addUserMessage'); + } + + addSystemMessage(_content) { + notImplementedError('addSystemMessage'); + } + + addAssistantMessage(_content) { + notImplementedError('addAssistantMessage'); + } + + addErrorMessage(_error) { + notImplementedError('addErrorMessage'); + } +} + +// to see if i need this +export enum ModelConnectionState { + RUNNING, + DONE, + ERROR, +} diff --git a/src/extensions/query-translator/clients/OpenAi/OpenAiClient.ts b/src/extensions/query-translator/clients/OpenAi/OpenAiClient.ts new file mode 100644 index 000000000..fb3125141 --- /dev/null +++ b/src/extensions/query-translator/clients/OpenAi/OpenAiClient.ts @@ -0,0 +1,154 @@ +import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum, Configuration, OpenAIApi } from 'openai'; +import { reportTypesToDesc, reportExampleQueries } from '../const'; +import { ModelClient } from '../ModelClient'; +import { Status } from '../../component/ClientSettings'; + +const consoleLogAsync = async (message: string, other?: any) => { + await new Promise((resolve) => setTimeout(resolve, 0)).then(() => console.info(message, other)); +}; + +export class OpenAiClient extends ModelClient { + modelType: string | undefined; + + createSystemMessage: any; + + modelClient!: OpenAIApi; + + driver: any; + + constructor(settings) { + super(settings); + } + + async validateQuery(message, database) { + let query = message.content; + let isValid = false; + let errorMessage = ''; + try { + let res = await this.queryDatabase(`EXPLAIN ${query}`, database); + isValid = true; + } catch (e) { + isValid = false; + errorMessage = e.message; + } + return [isValid, errorMessage]; + } + + /** + * Function used to create the OpenAiApi object. + * */ + setModelClient() { + const configuration = new Configuration({ + apiKey: this.apiKey, + }); + this.modelClient = new OpenAIApi(configuration); + } + + /** + * + * @param setIsAuthenticated If defined, is a function used to set the authentication result (for example, set function of a state variable) + * @returns True if we client can authenticate, False otherwise + */ + async authenticate( + setIsAuthenticated = (boolean) => { + let x = boolean; + } + ) { + try { + let tmp = await this.getListModels(); + // Can be used in async mode without awaiting + // by passing down a function to set the authentication result + setIsAuthenticated(tmp.length > 0 ? Status.AUTHENTICATED : Status.ERROR); + return tmp.length > 0; + } catch (e) { + consoleLogAsync('Authentication went wrong: ', e); + return false; + } + } + + /** + * Used also to check authentication + * @returns list of models available for this client + */ + async getListModels() { + let res; + try { + if (!this.modelClient) { + throw new Error('no client defined'); + } + let req = await this.modelClient.listModels(); + // Extracting the names + res = req.data.data.map((x) => x.id).filter((x) => x.includes('gpt-')); + } catch (e) { + consoleLogAsync('Error while loading the model list: ', e); + res = []; + } + return res; + } + + setApiKey(apiKey) { + this.apiKey = apiKey; + const configuration = new Configuration({ + apiKey: apiKey, + }); + this.modelClient = new OpenAIApi(configuration); + } + + setDriver(driver) { + this.driver = driver; + } + + setListAvailableModels(listModels) { + this.listAvailableModels = listModels; + } + + setModelType(modelType) { + this.modelType = modelType; + } + + /** + * Function used to create a message sent from the user to the model. + * @param content Content of the message (the message wrote from the UI) + * @param reportType Type of report needed + * @param plain If True, return content itself, otherwise the message with all the prompting needed. + * @returns + */ + addUserMessage(content, reportType, plain = false) { + let queryExample = reportExampleQueries[reportType]; + let finalMessage = `${content}. Please use the following query structure as an example for ${reportTypesToDesc[reportType]}: + ${queryExample} + Remember to respect the schema and remove any unnecessary comments or explanations from your result.`; + return { role: ChatCompletionRequestMessageRoleEnum.User, content: plain ? content : finalMessage }; + } + + addSystemMessage(content) { + return { role: ChatCompletionRequestMessageRoleEnum.System, content: content }; + } + + addAssistantMessage(content) { + return { role: ChatCompletionRequestMessageRoleEnum.Assistant, content: content }; + } + + addErrorMessage(error) { + // let finalMessage = `Please fix the query accordingly to this error: ${error}. Plain cypher code, no comments and no explanations and no unrequired symbols. Remember to respect the schema. Please remove any comment or explanation from your result`; + let finalMessage = `Error: ${error}. Please correct the query based on the provided error message. Ensure the query follows the expected format, adheres to the schema, and does not contain any comments, explanations, or unnecessary symbols. Please remove any comments or explanations from the query result.`; + return { role: ChatCompletionRequestMessageRoleEnum.User, content: finalMessage }; + } + + getMessageContent(message: ChatCompletionRequestMessage) { + return message.content; + } + + async chatCompletion(history) { + const completion = await this.modelClient.createChatCompletion({ + model: this.modelType, + messages: history, + }); + // If the status is correct + if (completion.status == 200 && completion.data && completion.data.choices && completion.data.choices[0].message) { + let { message } = completion.data.choices[0]; + return message; + } + throw Error(`Request returned with status: ${completion.status}`); + } +} diff --git a/src/extensions/query-translator/clients/OpenAi/OpenAiLogo.png b/src/extensions/query-translator/clients/OpenAi/OpenAiLogo.png new file mode 100644 index 000000000..0f237a226 Binary files /dev/null and b/src/extensions/query-translator/clients/OpenAi/OpenAiLogo.png differ diff --git a/src/extensions/query-translator/clients/VertexAiClient.ts b/src/extensions/query-translator/clients/VertexAiClient.ts new file mode 100644 index 000000000..40d0caa0f --- /dev/null +++ b/src/extensions/query-translator/clients/VertexAiClient.ts @@ -0,0 +1,7 @@ +import { ModelClient } from './ModelClient'; + +const consoleLogAsync = async (message: string, other?: any) => { + await new Promise((resolve) => setTimeout(resolve, 0)).then(() => console.info(message, other)); +}; + +export class VertexAiClient extends ModelClient {} diff --git a/src/extensions/query-translator/clients/const.ts b/src/extensions/query-translator/clients/const.ts new file mode 100644 index 000000000..ac6362c0f --- /dev/null +++ b/src/extensions/query-translator/clients/const.ts @@ -0,0 +1,123 @@ +export const nodePropsQuery = `CALL apoc.meta.data() +YIELD label, other, elementType, type, property +WHERE NOT type = "RELATIONSHIP" AND elementType = "node" +WITH label AS nodeLabels, collect(property) AS properties +RETURN {labels: nodeLabels, properties: properties} AS output +`; + +export const relPropsQuery = ` +CALL apoc.meta.data() +YIELD label, other, elementType, type, property +WHERE NOT type = "RELATIONSHIP" AND elementType = "relationship" +WITH label AS nodeLabels, collect(property) AS properties +RETURN {type: nodeLabels, properties: properties} AS output +`; + +export const relQuery = ` +CALL apoc.meta.data() +YIELD label, other, elementType, type, property +WHERE type = "RELATIONSHIP" AND elementType = "node" +RETURN {source: label, relationship: property, target: other} AS output +`; + +export const reportTypesToDesc = { + table: 'Multiple variables representing property values of nodes and relationships.', + graph: + 'Multiple variables representing nodes objects and relationships objects inside the graph. Please return also the relationship objects.', + 'Bar Chart': 'Two variables named category(a String value) and value(numeric value).', + 'Line Chart': 'Two numeric variables named x and y.', + sunburst: 'Two variables named Path(list of strings) and value(a numerical value).', + 'Circle Packing': 'Two variables named Path(a list of strings) and value(a numerical value).', + choropleth: 'Two variables named code(a String value) and value(a numerical value).', + 'Area Map': 'Two variables named code(a String value) and value(a numerical value).', + treemap: 'Two variables named Path(a list of strings) and value(a numerical value).', + 'Radar Chart': 'Multiple variables representing property values of nodes and relationships.', + 'Sankey Chart': + 'Three variables, two being a node object (and not a property value) and one representing a relationship object (and not a property value).', + map: 'multiple variables representing nodes objects(should contain spatial propeties) and relationship objects.', + 'Single Value': 'A single value of a single variable.', + 'Gauge Chart': 'A single value of a single variable.', + 'Raw JSON': 'The Cypher query must return a JSON object that will be displayed as raw JSON data.', + 'Pie Chart': 'Two variables named category and value.', +}; + +export const reportExampleQueries = { + table: 'MATCH (n:Movie)<-[:ACTED_IN]-(p:Person) RETURN n.title, n.released, count(p) as actors', + graph: `MATCH (p:Person)-[a:ACTED_IN]->(m:Movie) WHERE m.title = 'The Matrix' RETURN p, a, m`, + 'Bar Chart': 'MATCH (p:Person)-[e]->(m:Movie) RETURN m.title as Title, COUNT(p) as People', + 'Line Chart': 'MATCH (p:Person) RETURN (p.born/10)*10 as Decade, COUNT(p) as People ORDER BY Decade ASC', + sunburst: `MATCH path=(:Company{name:'NeoDash'})-[:HAS_DEPARTMENT*]->(:Department) WITH nodes(path) as no WITH no, last(no) as leaf WITH [n IN no[..-1] | n.name] AS result, sum(leaf.employees) as val RETURN result, val`, + 'Circle Packing': `MATCH path=(:Company{name:'NeoDash'})-[:HAS_DEPARTMENT*]->(:Department) WITH nodes(path) as no WITH no, last(no) as leaf WITH [n IN no[..-1] | n.name] AS result, sum(leaf.employees) as val RETURN result, val`, + choropleth: `MATCH (:Company{name:'NeoDash'})-[:HAS_DEPARTMENT]->(:Department)<-[:IN_DEPARTMENT]-(e:Employee),(e)-[:LIVES_IN]->(c:Country) WITH c.code as code, count(e) as value RETURN code, value`, + 'Area Map': `MATCH (:Company{name:'NeoDash'})-[:HAS_DEPARTMENT]->(:Department)<-[:IN_DEPARTMENT]-(e:Employee), + (e)-[:LIVES]->(city:City)-[:IN_COUNTRY]->(country:Country) + WITH city, country + CALL { + WITH country + RETURN country.countryCode as code, count(*) as value + UNION + WITH city + RETURN city.countryCode as code, count(*) as value + } + WITH code, sum(value) as totalCount + RETURN code,totalCount`, + treemap: `MATCH path=(:Company{name:'NeoDash'})-[:HAS_DEPARTMENT*]->(:Department) WITH nodes(path) as no WITH no, last(no) as leaf WITH [n IN no[..-1] | n.name] AS result, sum(leaf.employees) as val RETURN result, val`, + 'Radar Chart': `MATCH (s:Skill) + MATCH (:Player{name:"Messi"})-[h1:HAS_SKILL]->(s) + MATCH (:Player{name:"Mbappe"})-[h2:HAS_SKILL]->(s) + MATCH (:Player{name:"Benzema"})-[h3:HAS_SKILL]->(s) + MATCH (:Player{name:"C Ronaldo"})-[h4:HAS_SKILL]->(s) + MATCH (:Player{name:"Lewandowski"})-[h5:HAS_SKILL]->(s) + RETURN s.name as Skill, h1.value as Messi, h2.value as Mbappe, h3.value as Benzema, h4.value as Ronaldo, h5.value as Lewandowski`, + 'Sankey Chart': 'MATCH (p:Person)-[r:RATES]->(m:Movie) RETURN p, r, m', + map: 'MATCH (b:Brewery) RETURN b', + 'Single Value': 'MATCH (n) RETURN COUNT(n)', + 'Gauge Chart': 'MATCH (c:CPU) WHERE c.id = 1 RETURN c.load_percentage * 100', + 'Raw JSON': 'MATCH (n) RETURN COUNT(n)', + 'Pie Chart': 'Match (n:Person)-[e]->(m:Movie) RETURN m.title as Title, COUNT(p) as People LIMIT 10', +}; + +export const TASK_DEFINITION = `Task: Generate Cypher queries to query a Neo4j graph database based on the provided schema definition. These queries will be used inside NeoDash reports. +Documentation for NeoDash is here : https://neo4j.com/labs/neodash/2.2/ +Instructions: +Use only the provided relationship types and properties. +Do not use any other relationship types or properties that are not provided. +The Cypher RETURN clause must contained certain variables, based on the report type asked for. +Report types : +Table - Multiple variables representing property values of nodes and relationships. +Graph - Multiple variables representing nodes objects and relationships objects inside the graph. +Bar Chart - Two variables named category(a String value) and value(numeric value). +Line Chart - Two numeric variables named x and y. +Sunburst - Two variables named Path(list of strings) and value(a numerical value). +Circle Packing - Two variables named Path(a list of strings) and value(a numerical value). +Choropleth - Two variables named code(a String value) and value(a numerical value). +Area Map - Two variables named code(a String value) and value(a numerical value). +Treemap - Two variables named Path(a list of strings) and value(a numerical value). +Radar Chart - Multiple variables representing property values of nodes and relationships. +Sankey Chart - Three variables, two being a node object (and not a property value) and one representing a relationship object (and not a property value). +Map - multiple variables representing nodes objects(should contain spatial propeties) and relationship objects. +Single Value - A single value of a single variable. +Gauge Chart - A single value of a single variable. +Raw JSON - The Cypher query must return a JSON object that will be displayed as raw JSON data. +Pie Chart - Two variables named category and value.`; + +export const MAX_NUM_VALIDATION = 1; + +/** + * Function to create, from the relQuery result, the patterns + * @param rels Result got from relQuery query + * @returns A string containing all the possible patterns + */ +export function createRelPattern(rels) { + let res: string[] = []; + try { + // For each relationship + rels.forEach((rel) => { + // For each possible target + rel.target.forEach((trg) => res.push(`(:${rel.source})-[:${rel.relationship}]->(:${trg})`)); + }); + return res.join(','); + } catch (e) { + console.log(e); + } +} diff --git a/src/extensions/query-translator/component/ClientSettings.tsx b/src/extensions/query-translator/component/ClientSettings.tsx new file mode 100644 index 000000000..7acdf33ec --- /dev/null +++ b/src/extensions/query-translator/component/ClientSettings.tsx @@ -0,0 +1,227 @@ +import React, { useCallback, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { debounce, List, ListItem } from '@mui/material'; +import { getModelClientObject, getQueryTranslatorDefaultConfig } from '../QueryTranslatorConfig'; +import { getQueryTranslatorSettings } from '../state/QueryTranslatorSelector'; +import NeoSetting from '../../../component/field/Setting'; +import { + deleteAllMessageHistory, + setClientSettings, + setGlobalModelClient, + setModelProvider, +} from '../state/QueryTranslatorActions'; +import { + PlayCircleIconSolid, + CheckCircleIconSolid, + PlayIconSolid, + ExclamationTriangleIconSolid, +} from '@neo4j-ndl/react/icons'; +import { Button, IconButton } from '@neo4j-ndl/react'; +import { modelClientInitializationThunk } from '../state/QueryTranslatorThunks'; + +const update = (state, mutations) => Object.assign({}, state, mutations); + +export enum Status { + NOT_AUTHENTICATED, + AUTHENTICATED, + ERROR, +} + +// TODO: the following +// 1. the settings modal should save only when all the required fields are defined and we can correctly authenticate +export const ClientSettings = ({ + modelProvider, + settingState, + setSettingsState, + authenticate, + updateModelProvider, + updateClientSettings, + deleteAllMessageHistory, + handleClose, +}) => { + const defaultSettings = getQueryTranslatorDefaultConfig(modelProvider); + const requiredSettings = Object.keys(defaultSettings).filter((setting) => defaultSettings[setting].required); + const [localSettings, setLocalSettings] = React.useState(settingState); + + const [status, setStatus] = React.useState(Status.NOT_AUTHENTICATED); + const [settingChoices, setSettingChoices] = React.useState({}); + + /** + * Method used to update a certain field inside a state object. + * @param field Name of the field to update + * @param value Value to set for the specified field + * @param stateObj Object to update + * @param setFunction Function used to update stateObj + */ + const updateSpecificFieldInStateObject = (field: string, value: any, stateObj, setFunction) => { + const entry = {}; + entry[field] = value; + setFunction(update(stateObj, entry)); + }; + + const debouncedUpdateSpecificFieldInStateObject = useCallback(debounce(updateSpecificFieldInStateObject, 500), []); + + /** + * Function used from each setting to understand if it needs to be disabled + * @param setting Name of the setting to check + * @returns False if not disabled, otherwise True + */ + function checkIfDisabled(setting) { + let tmp = defaultSettings[setting]; + if (tmp.required || status == Status.AUTHENTICATED) { + return false; + } + return !requiredSettings.every((e) => settingState[e]); + } + + // Effect used to trigger the population of the settings when the user inserts a correct apiKey + useEffect(() => { + let localClientTmp = getModelClientObject(modelProvider, settingState); + if (status == Status.AUTHENTICATED) { + setGlobalModelClient(localClientTmp); + } else { + setGlobalModelClient(undefined); + } + let tmpSettingsChoices = {}; + Object.keys(defaultSettings).map((setting) => { + tmpSettingsChoices[setting] = setChoices(setting, localClientTmp); + }); + }, [status]); + + /** + * Function used to handle the definition of the choices param inside the settings form. + * If needed, it will get the choices from the client + * @param setting Name of the setting that we need to populate + * @param modelClient Client to call the AI model + */ + function setChoices(setting, modelClient) { + let choices = defaultSettings[setting].values ? defaultSettings[setting].values : []; + let { methodFromClient } = defaultSettings[setting]; + if (methodFromClient && status == Status.AUTHENTICATED) { + modelClient[methodFromClient]().then((value) => { + updateSpecificFieldInStateObject(setting, value, settingChoices, setSettingChoices); + }); + } else { + updateSpecificFieldInStateObject(setting, choices, settingChoices, setSettingChoices); + } + } + + const getBackgroundColor = (status) => { + if (status == Status.AUTHENTICATED) { + return 'green'; + } else if (status == Status.NOT_AUTHENTICATED) { + return 'orange'; + } + return 'red'; + }; + + // Prevent authentication if all required fields are not full (EX: look at checkIfDisabled) + const authButton = ( + { + e.preventDefault(); + updateModelProvider(modelProvider); + updateClientSettings(settingState); + authenticate(setStatus); + }} + clean + style={{ + marginTop: 24, + marginRight: 28, + color: 'white', + backgroundColor: getBackgroundColor(status), + }} + size='medium' + > + {status == Status.AUTHENTICATED ? ( + + ) : status == Status.NOT_AUTHENTICATED ? ( + + ) : ( + + )} + + ); + + const component = ( + + {/* Only render the base settings (required for auth) if no authentication is available. */} + {Object.keys(defaultSettings) + .filter((setting) => defaultSettings[setting].authentication == true || status == Status.AUTHENTICATED) + .map((setting) => { + let disabled = checkIfDisabled(setting); + return ( + + { + updateSpecificFieldInStateObject(setting, e, localSettings, setLocalSettings); + debouncedUpdateSpecificFieldInStateObject(setting, e, settingState, setSettingsState); + + if (defaultSettings[setting].hasAuthButton) { + setStatus(Status.NOT_AUTHENTICATED); + } + }} + /> + {/* TODO: Only show auth button if all required fields are filled in. */} + {defaultSettings[setting].hasAuthButton == true ? authButton : <>} + + ); + })} +
+ {status == Status.AUTHENTICATED && Object.keys(defaultSettings).every((n) => localSettings[n] !== undefined) ? ( + <> + + + + ) : ( + <> + )} +
+ ); + return component; +}; + +const mapStateToProps = (state) => ({ + settings: getQueryTranslatorSettings(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + setGlobalModelClient: (modelClient) => { + dispatch(setGlobalModelClient(modelClient)); + }, + authenticate: (setIsAuthenticated) => { + dispatch(modelClientInitializationThunk(setIsAuthenticated)); + }, + updateModelProvider: (modelProviderState) => { + dispatch(setModelProvider(modelProviderState)); + }, + updateClientSettings: (settingState) => { + dispatch(setClientSettings(settingState)); + }, + deleteAllMessageHistory: () => { + dispatch(deleteAllMessageHistory()); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ClientSettings); diff --git a/src/extensions/query-translator/component/LoadingIcon.tsx b/src/extensions/query-translator/component/LoadingIcon.tsx new file mode 100644 index 000000000..bf185806a --- /dev/null +++ b/src/extensions/query-translator/component/LoadingIcon.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import logo from '../clients/OpenAi/OpenAiLogo.png'; + +export const GPT_LOADING_ICON = ( +
+
+ +
+ Calling OpenAI... +
+); diff --git a/src/extensions/query-translator/component/OverrideCardQueryEditor.tsx b/src/extensions/query-translator/component/OverrideCardQueryEditor.tsx new file mode 100644 index 000000000..2eaeb1857 --- /dev/null +++ b/src/extensions/query-translator/component/OverrideCardQueryEditor.tsx @@ -0,0 +1,218 @@ +import React, { useCallback, useContext, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { Button, Switch } from '@neo4j-ndl/react'; +import NeoCodeEditorComponent, { + DEFAULT_CARD_SETTINGS_HELPER_TEXT_STYLE, +} from '../../../component/editor/CodeEditorComponent'; +import { getReportTypes } from '../../ExtensionUtils'; +import { queryTranslationThunk } from '../state/QueryTranslatorThunks'; +import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; +import debounce from 'lodash/debounce'; +import { updateLastMessage } from '../state/QueryTranslatorActions'; +import { createNotification } from '../../../application/ApplicationActions'; +import { getLastMessage, QUERY_TRANSLATOR_EXTENSION_NAME } from '../state/QueryTranslatorSelector'; +import { GPT_LOADING_ICON } from './LoadingIcon'; +import { + deleteSessionStoragePrepopulationReportFunction, + setSessionStoragePrepopulationReportFunction, +} from '../../state/ExtensionActions'; +import { getPrepopulateReportExtension } from '../../state/ExtensionSelectors'; + +// TODO: right now if we change the database in the cardSelector, it should forgot the card history +export const NeoOverrideCardQueryEditor = ({ + pagenumber, + reportId, + cypherQuery, + extensions, + reportType, + updateCypherQuery, + lastMessage, + prepopulateExtensionName, + translateQuery, + updateEnglishQuery, + displayError, + setPrepopulationReportFunction, + deletePrepopulationReportFunction, +}) => { + enum Language { + ENGLISH, + CYPHER, + } + + const [language, setLanguage] = React.useState(Language.CYPHER); + const [runningTranslation, setRunningTranslation] = React.useState(false); + const [englishQuestion, setEnglishQuestion] = React.useState(''); + const debouncedEnglishQuestionUpdate = useCallback(debounce(updateEnglishQuery, 250), []); + + useEffect(() => { + // Reset text to the dashboard state when the page gets reorganized. + if (lastMessage !== englishQuestion) { + setEnglishQuestion(lastMessage); + } + }, [lastMessage]); + + const reportTypes = getReportTypes(extensions); + + const cypherEditor = ( + updateCypherQuery(value)} + placeholder={`Enter Cypher here...`} + /> + ); + + function updateEnglishQuestion(value) { + debouncedEnglishQuestionUpdate(pagenumber, reportId, value); + setEnglishQuestion(value); + } + + // To prevent a bug with the code editor component, we wrap it in an extra enclosing bracket. + const englishEditor = ( +
+ { + setPrepopulationReportFunction(reportId); + updateEnglishQuestion(value); + }} + style={{ border: '1px dashed darkgrey' }} + placeholder={`Enter English here...`} + /> +
+ ); + + const { driver } = useContext(Neo4jContext); + + function triggerTranslation() { + setRunningTranslation(true); + translateQuery( + pagenumber, + reportId, + englishQuestion, + reportType, + driver, + () => { + setRunningTranslation(false); + }, + (e) => { + setRunningTranslation(false); + console.log(e); + displayError(e); + } + ); + } + + return ( +
+ {runningTranslation ? ( +
{GPT_LOADING_ICON}
+ ) : ( + <> + + + + + + + +
Cypher + { + if (language == Language.ENGLISH) { + setLanguage(Language.CYPHER); + deletePrepopulationReportFunction(reportId); + } else { + setLanguage(Language.ENGLISH); + } + }} + className='n-ml-2' + /> +   English + {/* Only show translation button if there's something new to translate */} + {language == Language.ENGLISH ? ( + + ) : ( + <> + )} +
+ {language == Language.CYPHER ? cypherEditor : englishEditor} +
+ {language == Language.ENGLISH ? ( + <> + For best results, use a descriptive question. See also the{' '} + + documentation + + . + + ) : ( + reportTypes[reportType] && reportTypes[reportType].helperText + )} +
+ + )} +
+ ); +}; + +const mapStateToProps = (state, ownProps) => ({ + lastMessage: getLastMessage(state, ownProps.pagenumber, ownProps.reportId), + prepopulateExtensionName: getPrepopulateReportExtension(state, ownProps.reportId), +}); + +const mapDispatchToProps = (dispatch) => ({ + translateQuery: (pagenumber, reportId, text, reportType, driver, onComplete, onError, onRetry) => { + dispatch(queryTranslationThunk(pagenumber, reportId, text, reportType, driver, onComplete, onError, onRetry)); + }, + updateEnglishQuery: (pagenumber, reportId, message) => { + dispatch(updateLastMessage(message, pagenumber, reportId)); + }, + displayError: (message) => { + dispatch(createNotification('Error when translating the natural language query', message)); + }, + setPrepopulationReportFunction: (reportId) => { + dispatch(setSessionStoragePrepopulationReportFunction(reportId, QUERY_TRANSLATOR_EXTENSION_NAME)); + }, + deletePrepopulationReportFunction: (reportId) => { + dispatch(deleteSessionStoragePrepopulationReportFunction(reportId)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(NeoOverrideCardQueryEditor); diff --git a/src/extensions/query-translator/component/QueryTranslator.tsx b/src/extensions/query-translator/component/QueryTranslator.tsx new file mode 100644 index 000000000..de71fa9be --- /dev/null +++ b/src/extensions/query-translator/component/QueryTranslator.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { SideNavigationItem } from '@neo4j-ndl/react'; +import QueryTranslatorSettingsModal from './QueryTranslatorSettingsModal'; +import { Tooltip } from '@mui/material'; +import { ExclamationTriangleIconSolid, LanguageIconSolid } from '@neo4j-ndl/react/icons'; +import { getModelProvider } from '../state/QueryTranslatorSelector'; + +const QueryTranslatorButton = (active) => { + const [open, setOpen] = React.useState(false); + const button = ( +
+ + setOpen(true)} + icon={ + <> + + {/* TODO Use Needle Icon Badges when implemented. */} + {active.active == '' || active.active == undefined ? ( + + ) : ( + <> + )} + + } + > + Natural Language Queries + + +
+ ); + + const component = ( +
+ {button} + {open ? : <>} +
+ ); + + return component; +}; + +const mapStateToProps = (state) => ({ + active: getModelProvider(state), +}); + +const mapDispatchToProps = (_dispatch) => ({}); + +export default connect(mapStateToProps, mapDispatchToProps)(QueryTranslatorButton); diff --git a/src/extensions/query-translator/component/QueryTranslatorSettingsModal.tsx b/src/extensions/query-translator/component/QueryTranslatorSettingsModal.tsx new file mode 100644 index 000000000..c4d2f0f73 --- /dev/null +++ b/src/extensions/query-translator/component/QueryTranslatorSettingsModal.tsx @@ -0,0 +1,89 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { setClientSettings, setModelProvider } from '../state/QueryTranslatorActions'; +import { getQueryTranslatorSettings, getModelProvider } from '../state/QueryTranslatorSelector'; +import { SELECTION_TYPES } from '../../../config/CardConfig'; +import NeoSetting from '../../../component/field/Setting'; +import { QUERY_TRANSLATOR_CONFIG } from '../QueryTranslatorConfig'; +import ClientSettings from './ClientSettings'; +import { Dialog } from '@neo4j-ndl/react'; +import { modelClientInitializationThunk } from '../state/QueryTranslatorThunks'; + +export const QueryTranslatorSettingsModal = ({ + open, + setOpen, + modelProvider, + clientSettings, + updateClientSettings, + updateModelProvider, + initializeModelClient, +}) => { + const [modelProviderState, setModelProviderState] = React.useState(modelProvider); + const [settingsState, setSettingsState] = React.useState(clientSettings); + + // TODO: a user shouldn't be able to save a configuration if it's not correct and it didn't fill all the requirements + // DONE: by moving the storing logic only inside the start querying button + const handleCloseWithSave = () => { + updateModelProvider(modelProviderState); + updateClientSettings(settingsState); + setOpen(false); + initializeModelClient(); + }; + + const handleCloseWithoutSave = () => { + setOpen(false); + }; + + return ( + + LLM-Powered Natural Language Queries + + This extensions lets you create reports with natural language. Your queries (in English) are translated to + Cypher by a LLM provider of your choice. +
+
+ Keep in mind that the following data will be sent to a external API: +
    +
  • - Your database schema, including label names, relationship types, and property keys.
  • +
  • - Any natural language question that a user writes.
  • +
+
+
+ setModelProviderState(e)} + /> + {modelProviderState ? ( + + ) : ( + <>Select one of the available clients. + )} +
+
+ ); +}; +const mapStateToProps = (state) => ({ + clientSettings: getQueryTranslatorSettings(state), + modelProvider: getModelProvider(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + updateClientSettings: (settings) => dispatch(setClientSettings(settings)), + updateModelProvider: (modelProvider) => dispatch(setModelProvider(modelProvider)), + initializeModelClient: (setIsAuthenticated) => { + dispatch(modelClientInitializationThunk(setIsAuthenticated)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(QueryTranslatorSettingsModal); diff --git a/src/extensions/query-translator/state/QueryTranslatorActions.ts b/src/extensions/query-translator/state/QueryTranslatorActions.ts new file mode 100644 index 000000000..6cd24e808 --- /dev/null +++ b/src/extensions/query-translator/state/QueryTranslatorActions.ts @@ -0,0 +1,59 @@ +import { + deleteAllKeysInSessionStorageWithPrefix, + deleteSessionStorageValue, + SESSION_STORAGE_PREFIX, + setSessionStorageValue, +} from '../../../sessionStorage/SessionStorageActions'; +import { + getModelClientSessionStorageKey, + getSessionStorageHistoryKey, + QUERY_TRANSLATOR_HISTORY_PREFIX, +} from './QueryTranslatorSelector'; + +export const QUERY_TRANSLATOR_ACTION_PREFIX = 'DASHBOARD/EXTENSIONS/QUERY_TRANSLATOR/'; +export const QUERY_TRANSLATOR_SESSION_STORAGE_ACTION_PREFIX = `DASHBOARD/EXTENSIONS/QUERY_TRANSLATOR/${SESSION_STORAGE_PREFIX}/`; + +export const SET_MODEL_PROVIDER = `${QUERY_TRANSLATOR_ACTION_PREFIX}SET_MODEL_PROVIDER`; +export const setModelProvider = (modelProvider) => ({ + type: SET_MODEL_PROVIDER, + payload: { modelProvider }, +}); + +export const SET_CLIENT_SETTINGS = `${QUERY_TRANSLATOR_ACTION_PREFIX}SET_CLIENT_SETTINGS`; +export const setClientSettings = (settings) => ({ + type: SET_CLIENT_SETTINGS, + payload: { settings }, +}); + +export const SET_GLOBAL_MODEL_CLIENT = `${QUERY_TRANSLATOR_ACTION_PREFIX}SET_GLOBAL_MODEL_CLIENT`; +export const setGlobalModelClient = (modelClient) => + setSessionStorageValue(getModelClientSessionStorageKey(), modelClient); + +export const UPDATE_LAST_MESSAGE = `${QUERY_TRANSLATOR_ACTION_PREFIX}UPDATE_LAST_MESSAGE`; +/** + * Action to store the last message sent between a user and the query translator + * @param message History of messages between a card and the model + * @param pagenumber Index of the page related to the card + * @param cardId Id of the card inside the page + * @returns + */ +export const updateLastMessage = (message: string, pagenumber: number, cardId: string) => ({ + type: UPDATE_LAST_MESSAGE, + payload: { message, pagenumber, cardId }, +}); + +/** + * Action to add a new message to the history + * @param history History of messages between a card and the model + * @param pagenumber Index of the page related to the card + * @param cardId Id of the card inside the page + * @returns + */ + +export const updateMessageHistory = (cardHistory: any[], pagenumber: number, cardId: string) => + setSessionStorageValue(getSessionStorageHistoryKey(pagenumber, cardId), cardHistory); + +export const deleteMessageHistory = (pagenumber: number, cardId: string) => + deleteSessionStorageValue(getSessionStorageHistoryKey(pagenumber, cardId)); + +export const deleteAllMessageHistory = () => deleteAllKeysInSessionStorageWithPrefix(QUERY_TRANSLATOR_HISTORY_PREFIX); diff --git a/src/extensions/query-translator/state/QueryTranslatorReducer.ts b/src/extensions/query-translator/state/QueryTranslatorReducer.ts new file mode 100644 index 000000000..3035a14dc --- /dev/null +++ b/src/extensions/query-translator/state/QueryTranslatorReducer.ts @@ -0,0 +1,47 @@ +/** + * Reducers define changes to the application state when a given action + */ + +import { SET_MODEL_PROVIDER, SET_CLIENT_SETTINGS, UPDATE_LAST_MESSAGE } from './QueryTranslatorActions'; + +export const INITIAL_EXTENSION_STATE = { + modelProvider: '', // Name of the provider (defined in the config) + history: {}, // Objects that keeps, for every card, their history (to move to session store) + modelClient: '', // Object to connect with the model API (to move to session store) + settings: {}, // Settings needed by the client to operate + lastMessages: {}, +}; + +const update = (state, mutations) => Object.assign({}, state, mutations); + +export const queryTranslatorReducer = (state = INITIAL_EXTENSION_STATE, action: { type: any; payload: any }) => { + const { type, payload } = action; + + switch (type) { + case SET_MODEL_PROVIDER: { + const { modelProvider } = payload; + state = update(state, { modelProvider: modelProvider }); + return state; + } + case SET_CLIENT_SETTINGS: { + const { settings } = payload; + state = update(state, { settings: settings }); + return state; + } + case UPDATE_LAST_MESSAGE: { + const { message, pagenumber, cardId } = payload; + let newLastMessages = { ...state.lastMessages }; + if (newLastMessages && !newLastMessages[pagenumber]) { + newLastMessages[pagenumber] = {}; + newLastMessages[pagenumber][cardId] = message; + } else { + newLastMessages[pagenumber][cardId] = message; + } + state = update(state, { lastMessages: newLastMessages }); + return state; + } + default: { + return state; + } + } +}; diff --git a/src/extensions/query-translator/state/QueryTranslatorSelector.ts b/src/extensions/query-translator/state/QueryTranslatorSelector.ts new file mode 100644 index 000000000..3bb6531ae --- /dev/null +++ b/src/extensions/query-translator/state/QueryTranslatorSelector.ts @@ -0,0 +1,85 @@ +import { getSessionStorageValue } from '../../../sessionStorage/SessionStorageSelectors'; + +export const QUERY_TRANSLATOR_EXTENSION_NAME = 'query-translator'; +export const QUERY_TRANSLATOR_HISTORY_PREFIX = `${QUERY_TRANSLATOR_EXTENSION_NAME}_history__`; + +/** + * Creates a new composite key for RW operations against the SessionStorage. + */ +export const getSessionStorageHistoryKey = (pagenumber, cardId) => { + return `${QUERY_TRANSLATOR_HISTORY_PREFIX}__${pagenumber}__${cardId}`; +}; +/** + * Returns a key for RW operations against the SessionStorage. + */ +export const getModelClientSessionStorageKey = () => 'query_translator_model_client_tmp'; + +const checkExtensionConfig = (state: any) => { + return state.dashboard.extensions && state.dashboard.extensions[QUERY_TRANSLATOR_EXTENSION_NAME]; +}; + +export const getHistory = (state: any) => { + let history = checkExtensionConfig(state) && state.dashboard.extensions[QUERY_TRANSLATOR_EXTENSION_NAME].history; + return history != undefined && history ? history : {}; +}; + +export const getLastMessages = (state: any) => { + let lastMessages = + checkExtensionConfig(state) && state.dashboard.extensions[QUERY_TRANSLATOR_EXTENSION_NAME].lastMessages; + return lastMessages != undefined && lastMessages ? lastMessages : {}; +}; + +export const getQueryTranslatorSettings = (state: any) => { + let clientSettings = + checkExtensionConfig(state) && state.dashboard.extensions[QUERY_TRANSLATOR_EXTENSION_NAME].settings; + return clientSettings != undefined && clientSettings ? clientSettings : {}; +}; + +export const getModelProvider = (state: any) => { + let modelProvider = + checkExtensionConfig(state) && state.dashboard.extensions[QUERY_TRANSLATOR_EXTENSION_NAME].modelProvider; + return modelProvider != undefined && modelProvider ? modelProvider : ''; +}; + +/** + * The extension keeps, during one session, the client to connect to the model API. + * The client is kept only during the session, so every refresh it is deleted. + * @param state Current state of the session + * @returns Current model client + */ +export const getModelClient = (state: any) => { + let modelClient = getSessionStorageValue(state, getModelClientSessionStorageKey()); + return modelClient != undefined && modelClient ? modelClient : undefined; +}; + +/** + * The extension keeps, during one session, the history of messages between a user and a model. + * The history is kept only during the session, so every refresh it is deleted. + * @param state Current state of the session + * @param pagenumber Index of the page where the card lives + * @param cardId Index that identifies the card inside the page + * @returns history of messages between the user and the model within the context of that card (defaulted to []) + */ +export const getHistoryPerCard = (state: any, pagenumber, cardId) => { + let sessionStorageKey = getSessionStorageHistoryKey(pagenumber, cardId); + let cardHistory = getSessionStorageValue(state, sessionStorageKey); + return cardHistory != undefined && cardHistory ? cardHistory : []; +}; + +/** + * We persist the last message sent from the user to the model. + * @param state State of the application + * @param pagenumber Number of the page where the card lives + * @param id Unique identifier of the card + * @returns + */ +export const getLastMessage = (state: any, pagenumber, id) => { + let messages = getLastMessages(state); + let lastMessage = messages[pagenumber] && messages[pagenumber][id]; + return lastMessage !== undefined ? lastMessage : ''; +}; + +export const getApiKey = (state: any) => { + let settings = getQueryTranslatorSettings(state); + return settings.apiKey != undefined && settings.apiKey ? settings.apiKey : ''; +}; diff --git a/src/extensions/query-translator/state/QueryTranslatorThunks.ts b/src/extensions/query-translator/state/QueryTranslatorThunks.ts new file mode 100644 index 000000000..521811d5c --- /dev/null +++ b/src/extensions/query-translator/state/QueryTranslatorThunks.ts @@ -0,0 +1,135 @@ +import { updateReportQueryThunk } from '../../../card/CardThunks'; +import { getDatabase } from '../../../settings/SettingsSelectors'; +import { ModelClient } from '../clients/ModelClient'; +import { Status } from '../component/ClientSettings'; +import { getModelClientObject } from '../QueryTranslatorConfig'; +import { setGlobalModelClient, updateLastMessage, updateMessageHistory } from './QueryTranslatorActions'; +import { + getQueryTranslatorSettings, + getHistoryPerCard, + getModelClient, + getModelProvider, +} from './QueryTranslatorSelector'; + +const consoleLogAsync = async (message: string, other?: any) => { + await new Promise((resolve) => setTimeout(resolve, 0)).then(() => console.info(message, other)); +}; + +/** + * Thunk used to initialize the client model. To inizialize the client, we need to check that + * it can authenticate to it's service by calling its authenticate function + * @returns True if the client is created, otherwise False + */ +export const modelClientInitializationThunk = + ( + setIsAuthenticated = () => { + return Status.ERROR; + } + ) => + async (dispatch: any, getState: any) => { + const state = getState(); + + // Fetching the client properties from the state + let modelProvider = getModelProvider(state); + let settings = getQueryTranslatorSettings(state); + + if (modelProvider && settings) { + // Getting the correct ModelClient object + let tmpClient = getModelClientObject(modelProvider, settings); + + // Try authentication + let isAuthenticated = await tmpClient.authenticate(setIsAuthenticated); + + // If the authentication runs smoothly, store the client inside the application state + if (isAuthenticated) { + dispatch(setGlobalModelClient(tmpClient)); + return tmpClient; + } + } + return undefined; + }; + +/** + * Wrapper to get the model client from the state if already exists, otherwise it will recreate it and check that + * the authentication still works + * @returns An instance of the model client + */ +const getModelClientThunk = () => async (dispatch: any, getState: any) => { + const state = getState(); + let modelClient = getModelClient(state); + + // If not persisted in the current session, try to initialize a new model + if (!modelClient) { + let newClient = await dispatch(modelClientInitializationThunk()); + if (newClient) { + return newClient; + } + } + return modelClient; +}; + +/** + * Thunk used to handle the request to a model client for a query translation. + * @param pagenumber Index of the page where the card lives + * @param cardId Index that identifies a card inside its page + * @param message Message inserted by the user + * @param reportType Type of report used by the card calling the thunk + * @param driver Neo4j Driver used to fetch the schema from the database + * @param onComplete Function used to bring the query back to the calling component + * @param onError Function used to bring the error back to the calling component + * @param onRetry Function used to bring the current validation step counter + * back to the calling component + */ +export const queryTranslationThunk = + ( + pagenumber, + cardId, + message, + reportType, + driver, + onComplete = (e) => { + console.log(e); + }, + onError = (e) => { + console.log(e); + }, + onRetry = (e) => { + console.log(e); + } + ) => + async (dispatch: any, getState: any) => { + let query; + try { + const state = getState(); + const database = getDatabase(state, pagenumber, cardId); + dispatch(updateLastMessage(message, pagenumber, cardId)); + // Retrieving the model client from the state + let client: ModelClient = await dispatch(getModelClientThunk()); + if (client) { + // If missing, pass down the driver to persist it inside the client + if (!client.driver) { + client.setDriver(driver); + } + const messageHistory = getHistoryPerCard(state, pagenumber, cardId); + let translationRes = await client.queryTranslation(message, messageHistory, database, reportType, onRetry); + query = translationRes[0]; + let newHistory = translationRes[1]; + // The history will be updated only if the length is different (otherwise, it's the same history) + if (messageHistory.length < newHistory.length && query) { + dispatch(updateMessageHistory(newHistory, pagenumber, cardId)); + dispatch(updateReportQueryThunk(cardId, query)); + onComplete(query); + } + } else { + throw new Error( + 'Could not start client for the natural language translation, please check that you have an API key configured in the extension settings.' + ); + } + } catch (e) { + await consoleLogAsync( + `Something wrong happened while calling the model client for the card number ${cardId} inside the page ${pagenumber}: \n`, + { e } + ); + onError(e); + } + }; diff --git a/src/extensions/query-translator/util/Util.ts b/src/extensions/query-translator/util/Util.ts new file mode 100644 index 000000000..ee33de3f5 --- /dev/null +++ b/src/extensions/query-translator/util/Util.ts @@ -0,0 +1,44 @@ +import { createNotification } from '../../../application/ApplicationActions'; +import { toggleCardSettingsThunk } from '../../../card/CardThunks'; +import { QUERY_TRANSLATOR_EXTENSION_NAME } from '../state/QueryTranslatorSelector'; +import { queryTranslationThunk } from '../state/QueryTranslatorThunks'; + +/** + * This function translates a query using the specified driver and dispatches actions accordingly. + * It checks for the last message associated with the given pagenumber and ID from the QUERY_TRANSLATOR_EXTENSION_NAME extension. + * If a last message exists, it dispatches the queryTranslationThunk action with the necessary parameters. + * The result is set using the provided setResult function. + * If an error occurs during translation, a notification with an error message is dispatched. + * @param driver Neo4j driver + * @param dispatch Dispatch function to call actions + * @param pagenumber number of the page where the card lives + * @param id id of the card + * @param reportType Type of the report (needed for prompting logic) + * @param extensions Extension state + * @param setResult Functions to set the results back to the calling component + */ +export function translateQuery(driver, dispatch, pagenumber, id, reportType, extensions, setResult) { + const messages = extensions[QUERY_TRANSLATOR_EXTENSION_NAME].lastMessages; + let lastMessage = messages && messages[pagenumber] && messages[pagenumber][id] ? messages[pagenumber][id] : false; + + if (lastMessage) { + dispatch( + queryTranslationThunk( + pagenumber, + id, + lastMessage, + reportType, + driver, + (result) => { + setResult(result); + }, + (error) => { + // when on error - reopen the settings to avoid an infinitely looping loading screen + // TODO - still set the cypher query even though it fails + dispatch(createNotification('Error when translating the natural language query', error)); + dispatch(toggleCardSettingsThunk(id, true)); + } + ) + ); + } +} diff --git a/src/extensions/sidebar/SidebarConfig.ts b/src/extensions/sidebar/SidebarConfig.ts new file mode 100644 index 000000000..fd69b4840 --- /dev/null +++ b/src/extensions/sidebar/SidebarConfig.ts @@ -0,0 +1,65 @@ +import { SELECTION_TYPES } from '../../config/CardConfig'; + +// TODO: understand if we want pagination (strange styling). +const EXTENSIONS_CONFIG = { + 'node-sidebar': { + settings: { + colorProperty: { + label: 'Card Color Property', + type: SELECTION_TYPES.TEXT, + default: 'color', + }, + titleProperty: { + label: 'Card title property name', + type: SELECTION_TYPES.TEXT, + default: 'title', + }, + bodyProperty: { + label: 'Card body property name', + type: SELECTION_TYPES.TEXT, + default: 'description', + }, + maxRecords: { + label: 'Maximum number of records', + type: SELECTION_TYPES.NUMBER, + default: 100, + }, + refreshButtonEnabled: { + label: 'Refreshable', + type: SELECTION_TYPES.LIST, + values: [true, false], + default: false, + }, + resetParametersEnabled: { + label: 'Enable Reset Parameters', + type: SELECTION_TYPES.LIST, + values: [true, false], + default: false, + }, + drilldownEnabled: { + label: 'Enable Drilldown', + type: SELECTION_TYPES.LIST, + values: [true, false], + default: false, + }, + moveToPage: { + label: 'Drilldown to Page', + type: SELECTION_TYPES.LIST, + values: [], + default: 'Current Page', + needsStateValues: true, + }, + }, + }, +}; + +/** + * Function to get the extension config + * @param extensionName Name of the desired extension + * @returns Predefined fields of configuration for an extension + */ +export function getNodeSidebarDefaultConfig() { + return EXTENSIONS_CONFIG['node-sidebar'] && EXTENSIONS_CONFIG['node-sidebar'].settings + ? EXTENSIONS_CONFIG['node-sidebar'].settings + : {}; +} diff --git a/src/extensions/sidebar/SidebarDrawer.tsx b/src/extensions/sidebar/SidebarDrawer.tsx new file mode 100644 index 000000000..99667f529 --- /dev/null +++ b/src/extensions/sidebar/SidebarDrawer.tsx @@ -0,0 +1,170 @@ +import React, { useContext, useEffect, useState } from 'react'; +import SidebarDrawerHeader from './SidebarDrawerHeader'; +import { QueryStatus, runCypherQuery } from '../../report/ReportQueryRunner'; +import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; +import { connect } from 'react-redux'; +import { getSidebarDatabase, getSidebarOpened, getSidebarQuery } from './state/SidebarSelectors'; +import SidebarNodeCard from './component/SidebarNodeCard'; +import NeoCodeViewerComponent, { NoDrawableDataErrorMessage } from '../../component/editor/CodeViewerComponent'; +import { loadDatabaseListFromNeo4jThunk } from '../../dashboard/DashboardThunks'; +import { checkIfAllRecordsAreNodes, parseNodeRecordsToDictionaries } from '../../chart/graph/util/RecordUtils'; +import { getExtensionSettings } from '../state/ExtensionSelectors'; +import { getDashboardExtensions } from '../../dashboard/DashboardSelectors'; +import { Drawer, List, ListItem } from '@mui/material'; + +// The sidebar that appears on the left side of the dashboard. +export const NodeSidebarDrawer = ({ + extensions, + extensionSettings, + query, + database, + isOpen, + loadDatabaseListFromNeo4j, +}) => { + const open = extensions['node-sidebar'] && isOpen ? isOpen : false; + const [records, setRecords] = useState([]); + // List of records parsed from the result + const [parsedRecords, setParsedRecords] = useState([]); + // To notice, if the query is not present, we need to notify the user + const [status, setStatus] = useState(query == undefined ? QueryStatus.NO_QUERY : QueryStatus.RUNNING); + const [fields, setFields] = useState([]); + const [hasInvalidQuery, setHasInvalidQuery] = useState(false); + const [databaseListLoaded, setDatabaseListLoaded] = React.useState(false); + const [databaseList, setDatabaseList] = React.useState([]); + const [maxRecords, setMaxRecords] = React.useState( + extensionSettings && extensionSettings.maxRecords ? extensionSettings.maxRecords : 100 + ); + + // TODO - there is a lot of effects here, perhaps we can simplify. + // When the settings are changed, update the max records setting. + useEffect(() => { + let newMaxRecords = extensionSettings && extensionSettings.maxRecords ? extensionSettings.maxRecords : 100; + if (newMaxRecords != maxRecords) { + setMaxRecords(newMaxRecords); + } + }, [extensionSettings]); + + // On first initialization, load a database list from neo4j to use in the component. + useEffect(() => { + if (!databaseListLoaded) { + loadDatabaseListFromNeo4j(driver, (result) => { + let index = result.indexOf('system'); + if (index > -1) { + // only splice array when item is found + result.splice(index, 1); // 2nd parameter means remove one item only + } + setDatabaseList(result); + // At the start, set the DB of the drawer to the same db of the whole application + }); + setDatabaseListLoaded(true); + } + }, []); + + // Re-run the query when the query, database, or record max is updated. + useEffect(() => { + runCypher(); + }, [query, database, maxRecords]); + + // When the record or fields lists changed, regenerate the contents of the cards. + useEffect(() => { + if (!checkIfAllRecordsAreNodes(records, 0) || fields.length > 1) { + setParsedRecords([]); + setHasInvalidQuery(true); + } else { + setParsedRecords(parseNodeRecordsToDictionaries(records)); + setHasInvalidQuery(false); + } + }, [records, fields]); + + const { driver } = useContext(Neo4jContext); + + const runCypher = () => { + let useReturnValuesAsFields = true; + let useNodePropsAsFields = true; + let queryTimeLimit = 20; + runCypherQuery( + driver, + database, + query, + {}, + maxRecords, + setStatus, + setRecords, + setFields, + fields, + useNodePropsAsFields, + useReturnValuesAsFields, + true, + queryTimeLimit + ); + }; + + /** + * Function to create the correct message for the NeoCodeViewerComponent if there is no data to show to the user + * @param status status of the query + * @param records records brought back from the data + * @returns + */ + function getDrawerErrorMessage(status, records) { + let message = + status === QueryStatus.NO_QUERY + ? 'Use the settings (⋮) to \nspecify a query.' + : status === QueryStatus.NO_DATA + ? 'Query returned no data.' + : status === QueryStatus.ERROR + ? records[0] && records[0].error + ? records[0].error + : 'An undefined error occurred during the processing of the query.' + : ''; + return ; + } + const drawer = ( + + + {/* TODO: define generic body here (for now list of clickable cards) */} + {[QueryStatus.NO_DATA, QueryStatus.ERROR, QueryStatus.NO_QUERY].includes(status) ? ( + getDrawerErrorMessage(status, records) + ) : hasInvalidQuery ? ( + + ) : ( + + {parsedRecords.map((entity) => { + return ( + + + + ); + })} + + )} + + ); + + return drawer; +}; + +const mapStateToProps = (state) => ({ + extensions: getDashboardExtensions(state), + extensionSettings: getExtensionSettings(state, 'node-sidebar'), + query: getSidebarQuery(state), + database: getSidebarDatabase(state), + isOpen: getSidebarOpened(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + loadDatabaseListFromNeo4j: (driver, callback) => dispatch(loadDatabaseListFromNeo4jThunk(driver, callback)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(NodeSidebarDrawer); diff --git a/src/extensions/sidebar/SidebarDrawerButton.tsx b/src/extensions/sidebar/SidebarDrawerButton.tsx new file mode 100644 index 000000000..acafad70c --- /dev/null +++ b/src/extensions/sidebar/SidebarDrawerButton.tsx @@ -0,0 +1,34 @@ +import ReportIcon from '@mui/icons-material/Report'; +import React from 'react'; +import { connect } from 'react-redux'; +import { setExtensionSidebarOpen } from './state/SidebarActions'; +import { getSidebarOpened } from './state/SidebarSelectors'; +import { ListItem, ListItemIcon, ListItemText } from '@mui/material'; + +// TODO - rename to 'Node Sidebar Extension button' to reflect better the functionality. +const NeoNodeSidebarButton = ({ navItemClass, isOpen, setNodeSidebarOpened }) => { + const handleClick = () => { + setNodeSidebarOpened(!isOpen); + }; + + return ( +
+ + + + + + +
+ ); +}; + +const mapStateToProps = (state) => ({ + isOpen: getSidebarOpened(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + setNodeSidebarOpened: (open) => dispatch(setExtensionSidebarOpen(open)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(NeoNodeSidebarButton); diff --git a/src/extensions/sidebar/SidebarDrawerHeader.tsx b/src/extensions/sidebar/SidebarDrawerHeader.tsx new file mode 100644 index 000000000..2c8147228 --- /dev/null +++ b/src/extensions/sidebar/SidebarDrawerHeader.tsx @@ -0,0 +1,109 @@ +import React, { useCallback } from 'react'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import SidebarSettingsModal from './settings/SidebarSettingsModal'; +import { getSidebarGlobalParameters, getSidebarTitle } from './state/SidebarSelectors'; +import { setExtensionTitle } from './state/SidebarActions'; +import { connect } from 'react-redux'; +import RefreshIcon from '@mui/icons-material/Refresh'; +import ClearAllIcon from '@mui/icons-material/ClearAll'; +import { getExtensionSettings } from '../state/ExtensionSelectors'; +import { updateGlobalParameterThunk } from '../../settings/SettingsThunks'; +import { IconButton, TextField, Tooltip, debounce } from '@mui/material'; + +/** + * The editable header of the drawer, including the title and settings button. + * TODO - rename to 'Node Sidebar Header' to match new extension name. + */ +export const SidebarDrawerHeader = ({ + databaseList, + title, + extensionSettings, + sidebarGlobalParameters, + onTitleUpdate, + onGlobalParameterUpdate, + onManualRefreshDrawer, +}) => { + const [settingsOpen, setSettingsOpen] = React.useState(false); + const [headerTitle, setHeaderTitle] = React.useState(title); + const refreshable = extensionSettings.refreshButtonEnabled ? extensionSettings.refreshButtonEnabled : false; + const debouncedTitleUpdate = useCallback(debounce(onTitleUpdate, 250), []); + + function clearNodeSidebarParameters() { + sidebarGlobalParameters.forEach((key) => onGlobalParameterUpdate(key, undefined)); + } + const refreshButton = ( + + + + + + ); + + const clearParametersButton = ( + + + + + + ); + + return ( + + + + + + + + + +
+ { + setHeaderTitle(event.target.value); + debouncedTitleUpdate(event.target.value); + }} + /> + {refreshable ? refreshButton : <>}{extensionSettings.resetParametersEnabled ? clearParametersButton : <>} + + { + setSettingsOpen(true); + }} + > + + + + +
+ ); +}; + +const mapStateToProps = (state) => ({ + title: getSidebarTitle(state), + extensionSettings: getExtensionSettings(state, 'node-sidebar'), + sidebarGlobalParameters: getSidebarGlobalParameters(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + onTitleUpdate: (title: any) => { + dispatch(setExtensionTitle(title)); + }, + onGlobalParameterUpdate: (key: any, value: any) => { + dispatch(updateGlobalParameterThunk(key, value)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SidebarDrawerHeader); diff --git a/src/extensions/sidebar/component/SidebarNodeCard.tsx b/src/extensions/sidebar/component/SidebarNodeCard.tsx new file mode 100644 index 000000000..79d1fc9ee --- /dev/null +++ b/src/extensions/sidebar/component/SidebarNodeCard.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import SidebarNodeInspectionModal from './SidebarNodeInspectionModal'; +import { renderValueByType } from '../../../report/ReportRecordProcessing'; +import { Card, CardContent } from '@mui/material'; + +// TODO: Understand what to show (probably an option (maybe first three fields by default)) +export const SidebarNodeCard = ({ entity, extensionSettings }) => { + const [modalOpen, setModalOpen] = React.useState(false); + // TODO: understand how to bind colors + const colorProperty = extensionSettings.colorProperty ? extensionSettings.colorProperty : 'color'; + const titleProperty = extensionSettings.titleProperty ? extensionSettings.titleProperty : 'title'; + const bodyProperty = extensionSettings.bodyProperty ? extensionSettings.bodyProperty : 'body'; + + const content = ( + <> + { + setModalOpen(true); + }} + > + +

+ {entity.properties && entity.properties[titleProperty] + ? renderValueByType(entity.properties[titleProperty]) + : '(no title)'}{' '} +

+

+ {entity.properties && entity.properties[bodyProperty] + ? renderValueByType(entity.properties[bodyProperty]) + : '(no value)'}{' '} +

+
+
+ + + ); + return content; +}; + +export default SidebarNodeCard; diff --git a/src/extensions/sidebar/component/SidebarNodeInspectionModal.tsx b/src/extensions/sidebar/component/SidebarNodeInspectionModal.tsx new file mode 100644 index 000000000..599d16b10 --- /dev/null +++ b/src/extensions/sidebar/component/SidebarNodeInspectionModal.tsx @@ -0,0 +1,139 @@ +import React from 'react'; + +import CloseIcon from '@mui/icons-material/Close'; +import NeoGraphChart from '../../../chart/graph/GraphChart'; +import { connect } from 'react-redux'; +import { getSidebarDatabase, NODE_SIDEBAR_PARAM_PREFIX } from '../state/SidebarSelectors'; +import { NeoReportWrapper } from '../../../report/ReportWrapper'; +import GraphEntityInspectionTable from '../../../chart/graph/component/GraphEntityInspectionTable'; +import { getSelectionBasedOnFields } from '../../../chart/ChartUtils'; +import { getExtensionSettings } from '../../state/ExtensionSelectors'; +import { getPageNumber } from '../../../settings/SettingsSelectors'; +import { getPageNumbersAndNames } from '../../../dashboard/DashboardSelectors'; +import { setPageNumberThunk, updateGlobalParameterThunk } from '../../../settings/SettingsThunks'; +import { Badge, Button, Dialog, DialogContent, DialogTitle, IconButton } from '@mui/material'; +import { PlayArrow } from '@mui/icons-material'; + +// TODO: Same as 'Node card`, lets generalize this as a "detailed Node inspect modal". +const SidebarNodeInspectionModal = ({ + entity, + modalOpen, + setModalOpen, + database, + extensionSettings, + pageNumber, + pagesList, + setPageNumber, + onGlobalParameterUpdate, +}) => { + const [selection, setSelection] = React.useState({}); + const [selectedParameters, setSelectedParameters] = React.useState([]); + + // Get page to drill down to, if enabled + const drillDownPage = extensionSettings.moveToPage + ? extensionSettings.moveToPage === 'Current Page' + ? pageNumber + : parseInt(extensionSettings.moveToPage.split('/')[0]) + : pageNumber; + + const handleClose = () => { + setModalOpen(false); + }; + + /** + * Function that has the responsibility to manage the drill down logic when you click the button + */ + const handleDrilldown = () => { + selectedParameters.forEach((nodeParam) => { + onGlobalParameterUpdate(`${NODE_SIDEBAR_PARAM_PREFIX}${nodeParam}`, entity.properties[nodeParam]); + }); + handleClose(); + setPageNumber(drillDownPage); + }; + + return ( +
+ {modalOpen ? ( + + + {entity.labels.join(', ')} + + + + + + + +
+
+ +
+
+ +
+ {/* TODO: add missing parameters or make them optional in NeoReportWrapper */} + { + setSelection(getSelectionBasedOnFields(fields)); + }} + // TODO - fix arbitrary safety limit from '100' to something else here. + query={`MATCH (n) WHERE id(n) = ${entity.id} OPTIONAL MATCH p=(n)--() RETURN n,p LIMIT 100`} + ChartType={NeoGraphChart} + type={'graph'} + > +
+
+ {extensionSettings.drilldownEnabled ? ( + + ) : ( + <> + )} +
+ ) : ( + <> + )} +
+ ); +}; + +const mapStateToProps = (state) => ({ + database: getSidebarDatabase(state), + extensionSettings: getExtensionSettings(state, 'node-sidebar'), + pagesList: getPageNumbersAndNames(state), + pageNumber: getPageNumber(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + setPageNumber: (newIndex: number) => { + dispatch(setPageNumberThunk(newIndex)); + }, + onGlobalParameterUpdate: (key: any, value: any) => { + dispatch(updateGlobalParameterThunk(key, value)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SidebarNodeInspectionModal); diff --git a/src/extensions/sidebar/settings/SidebarSettingsForm.tsx b/src/extensions/sidebar/settings/SidebarSettingsForm.tsx new file mode 100644 index 000000000..1b6d1326d --- /dev/null +++ b/src/extensions/sidebar/settings/SidebarSettingsForm.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import NeoSetting from '../../../component/field/Setting'; +import { getPageNumbersAndNames } from '../../../dashboard/DashboardSelectors'; +import { getNodeSidebarDefaultConfig } from '../SidebarConfig'; +import { List, ListItem } from '@mui/material'; + +const update = (state, mutations) => Object.assign({}, state, mutations); + +// TODO - this is also very similar to the existing settings form in the card settings. +export const ExtensionSettingsForm = ({ + isAdvancedSettingsOpen, + setSettingsToSave, + extensionSettings, + defaultSettings, + pagesList, +}) => { + const [reportSettingsText, setReportSettingsText] = React.useState(extensionSettings); + + /** + * Given a setting name in input, return the state value needed to + * fill the choices in the advanced settings + * @param setting Name of the settings + * @returns Values got from the state + */ + function getSettingChoices(setting) { + let choices; + if (setting === 'moveToPage') { + choices = [...pagesList]; + choices.unshift(defaultSettings[setting].default); + } + return choices; + } + + const updateSpecificExtensionSetting = (field: string, value: any) => { + const entry = {}; + entry[field] = value; + setReportSettingsText(update(reportSettingsText, entry)); + setSettingsToSave(update(reportSettingsText, entry)); + }; + + return isAdvancedSettingsOpen ? ( + + {Object.keys(defaultSettings).map((setting) => { + let choices = defaultSettings[setting].values; + + // Some settings need to get their choices from the application state + if (defaultSettings[setting].needsStateValues) { + choices = getSettingChoices(setting); + } + return ( + + updateSpecificExtensionSetting(setting, e)} + /> + + ); + })} + + ) : ( + <> + ); +}; + +const mapStateToProps = (state) => ({ + defaultSettings: getNodeSidebarDefaultConfig(), + pagesList: getPageNumbersAndNames(state), +}); + +const mapDispatchToProps = (_dispatch) => ({}); + +export default connect(mapStateToProps, mapDispatchToProps)(ExtensionSettingsForm); diff --git a/src/extensions/sidebar/settings/SidebarSettingsModal.tsx b/src/extensions/sidebar/settings/SidebarSettingsModal.tsx new file mode 100644 index 000000000..e66d6aacf --- /dev/null +++ b/src/extensions/sidebar/settings/SidebarSettingsModal.tsx @@ -0,0 +1,179 @@ +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import NeoCodeEditorComponent from '../../../component/editor/CodeEditorComponent'; +import { getSidebarDatabase, getSidebarQuery } from '../state/SidebarSelectors'; +import { setExtensionDatabase, setExtensionQuery, setExtensionSettings } from '../state/SidebarActions'; +import NeoField from '../../../component/field/Field'; +import { applicationGetConnectionDatabase } from '../../../application/ApplicationSelectors'; +import ExtensionSettingsForm from './SidebarSettingsForm'; +import SaveIcon from '@mui/icons-material/Save'; +import { getExtensionSettings } from '../../state/ExtensionSelectors'; +import { + Badge, + Dialog, + DialogContent, + DialogTitle, + FormControlLabel, + FormGroup, + IconButton, + MenuItem, + Switch, +} from '@mui/material'; + +/** + * TODO: lets also generalize this as a 'pop-uppable report'. + * Perhaps we can even extend the Report component or generalize somehow. + */ +const SidebarSettingsModal = ({ + databaseList, + settingsOpen, + setSettingsOpen, + extensionSettings, + query, + database, + onQueryUpdate, + onSettingsUpdate, + onDatabaseChanged, + applicationDatabase, +}) => { + const [queryText, setQueryText] = React.useState(query); + const [databaseText, setDatabaseText] = React.useState(database); + const [isAdvancedSettingsOpen, setIsAdvancedSettingsOpen] = React.useState(false); + const [settingsToSave, setSettingsToSave] = React.useState(extensionSettings); + + /** + * Changing the global state only when needed + */ + const handleClose = () => { + setSettingsOpen(false); + + if (JSON.stringify(settingsToSave) !== JSON.stringify(extensionSettings)) { + // When saving, all the values that are False in TS ("", False, {}, 0 as a Number) will be filtered out + const filtered = Object.keys(settingsToSave) + .filter((key) => settingsToSave[key]) + .reduce((obj, key) => { + obj[key] = settingsToSave[key]; + return obj; + }, {}); + + onSettingsUpdate(filtered); + } + + if (query !== queryText) { + onQueryUpdate(queryText); + } + if (database !== databaseText) { + onDatabaseChanged(databaseText); + } + }; + + // On startup, if no specific database was defined, default to 'neo4j'. + useEffect(() => { + if (databaseText === '') { + let firstDb = applicationDatabase ? applicationDatabase : 'neo4j'; + setDatabaseText(firstDb); + } + }, []); + + return ( +
+ {settingsOpen ? ( + + + Node Sidebar Settings + + + + + + + + ( + + {database} + + ))} + onChange={(value) => { + setDatabaseText(value); + }} + /> + <> +
+
+ { + setQueryText(value); + }} + placeholder={'Enter Cypher here...'} + /> +

+ {'The sidebar expects nodes to be returned. For each node, a card is rendered.'} +

+
+
+ + { + setIsAdvancedSettingsOpen(event.target.checked); + }} + color='default' + /> + } + labelPlacement='end' + label={
Advanced settings
} + /> +
+ +
+
+ ) : ( + <> + )} +
+ ); +}; + +const mapStateToProps = (state) => ({ + extensionSettings: getExtensionSettings(state, 'node-sidebar'), + query: getSidebarQuery(state), + database: getSidebarDatabase(state), + applicationDatabase: applicationGetConnectionDatabase(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + onQueryUpdate: (query) => dispatch(setExtensionQuery(query)), + onSettingsUpdate: (settings) => dispatch(setExtensionSettings(settings)), + onDatabaseChanged: (database: any) => { + dispatch(setExtensionDatabase(database)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SidebarSettingsModal); diff --git a/src/extensions/sidebar/state/SidebarActions.ts b/src/extensions/sidebar/state/SidebarActions.ts new file mode 100644 index 000000000..703b9a176 --- /dev/null +++ b/src/extensions/sidebar/state/SidebarActions.ts @@ -0,0 +1,32 @@ +export const NODE_SIDEBAR_ACTION_PREFIX = 'DASHBOARD/EXTENSIONS/NODE_SIDEBAR/'; + +export const UPDATE_EXTENSION_TITLE = `${NODE_SIDEBAR_ACTION_PREFIX}UPDATE_EXTENSION_TITLE`; +export const setExtensionTitle = (title: string) => ({ + type: UPDATE_EXTENSION_TITLE, + // TODO: Simplify naming in the payload for all extension actions. + payload: { title }, +}); + +export const UPDATE_EXTENSION_SETTINGS = `${NODE_SIDEBAR_ACTION_PREFIX}UPDATE_EXTENSION_SETTINGS`; +export const setExtensionSettings = (settings: any) => ({ + type: UPDATE_EXTENSION_SETTINGS, + payload: { settings }, +}); + +export const UPDATE_EXTENSION_QUERY = `${NODE_SIDEBAR_ACTION_PREFIX}UPDATE_EXTENSION_QUERY`; +export const setExtensionQuery = (query: any) => ({ + type: UPDATE_EXTENSION_QUERY, + payload: { query }, +}); + +export const UPDATE_EXTENSION_OPEN = `${NODE_SIDEBAR_ACTION_PREFIX}UPDATE_EXTENSION_OPEN`; +export const setExtensionSidebarOpen = (open: boolean) => ({ + type: UPDATE_EXTENSION_OPEN, + payload: { opened: open }, +}); + +export const UPDATE_EXTENSION_DATABASE = `${NODE_SIDEBAR_ACTION_PREFIX}UPDATE_EXTENSION_DATABASE`; +export const setExtensionDatabase = (database: string) => ({ + type: UPDATE_EXTENSION_DATABASE, + payload: { databaseName: database }, +}); diff --git a/src/extensions/sidebar/state/SidebarReducer.ts b/src/extensions/sidebar/state/SidebarReducer.ts new file mode 100644 index 000000000..437f1640e --- /dev/null +++ b/src/extensions/sidebar/state/SidebarReducer.ts @@ -0,0 +1,80 @@ +/** + * Reducers define changes to the application state when a given action + */ + +import { + UPDATE_EXTENSION_DATABASE, + UPDATE_EXTENSION_OPEN, + UPDATE_EXTENSION_QUERY, + UPDATE_EXTENSION_SETTINGS, + UPDATE_EXTENSION_TITLE, +} from './SidebarActions'; + +export const INITIAL_EXTENSION_STATE = { + settings: {}, + query: '', + database: '', + opened: false, + title: '', +}; + +const update = (state, mutations) => Object.assign({}, state, mutations); + +export const sidebarReducer = (state = INITIAL_EXTENSION_STATE, action: { type: any; payload: any }) => { + const { type, payload } = action; + switch (type) { + case UPDATE_EXTENSION_SETTINGS: { + const { settings } = payload; + const newState = { + ...state, + }; + newState.settings = settings; + return newState; + } + + case UPDATE_EXTENSION_QUERY: { + // Setting the extension opened to trigger its rendering + const { query } = payload; + + const newState = { + ...state, + }; + // Managing first creation + newState.query = query; + return newState; + } + case UPDATE_EXTENSION_OPEN: { + // Setting the extension opened to trigger its rendering + const { opened } = payload; + const newState = { + ...state, + }; + // Managing first creation + // TODO - this is a bit of a funky implementation, lets think if we can come up with a neater way. + // perhaps first creation is done when the extension is enabled for the first time. + newState.opened = opened; + return newState; + } + // An extension is binded to a db (can be different with the ones that you are binded to the card) + case UPDATE_EXTENSION_DATABASE: { + const { databaseName } = payload; + const newState = { + ...state, + }; + newState.database = databaseName; + return newState; + } + + case UPDATE_EXTENSION_TITLE: { + const { title } = payload; + const newState = { + ...state, + }; + newState.title = title; + return newState; + } + default: { + return state; + } + } +}; diff --git a/src/extensions/sidebar/state/SidebarSelectors.ts b/src/extensions/sidebar/state/SidebarSelectors.ts new file mode 100644 index 000000000..d5fc1f06e --- /dev/null +++ b/src/extensions/sidebar/state/SidebarSelectors.ts @@ -0,0 +1,29 @@ +// TODO - perhaps we can guarantee creation or something... lets think some more to avoid this check. + +import { getGlobalParameters, getSessionParameters } from '../../../settings/SettingsSelectors'; + +export const NODE_SIDEBAR_PARAM_PREFIX = 'neodash_node_sidebar_'; +export const getSidebarOpened = (state: any) => { + let res = state.dashboard.extensions && state.dashboard.extensions['node-sidebar']; + return res != undefined && res.opened ? res.opened : false; +}; + +export const getSidebarQuery = (state: any) => { + let res = state.dashboard.extensions && state.dashboard.extensions['node-sidebar']; + return res != undefined && res.query ? res.query : '\n\n\n\n'; +}; + +export const getSidebarDatabase = (state: any) => { + let res = state.dashboard.extensions && state.dashboard.extensions['node-sidebar']; + return res != undefined && res.database ? res.database : ''; +}; + +export const getSidebarTitle = (state: any) => { + let res = state.dashboard.extensions && state.dashboard.extensions['node-sidebar']; + return res != undefined && res.title ? res.title : ''; +}; + +export const getSidebarGlobalParameters = (state: any) => { + let globalParameters = Object.keys({ ...getGlobalParameters(state), ...getSessionParameters(state) }); + return globalParameters.filter((elem) => elem.startsWith(NODE_SIDEBAR_PARAM_PREFIX)); +}; diff --git a/src/extensions/state/ExtensionActions.ts b/src/extensions/state/ExtensionActions.ts new file mode 100644 index 000000000..4cf314567 --- /dev/null +++ b/src/extensions/state/ExtensionActions.ts @@ -0,0 +1,18 @@ +import { deleteSessionStorageValue, setSessionStorageValue } from '../../sessionStorage/SessionStorageActions'; +import { getPrepopulationReportExtensionSessionStorageKey } from './ExtensionSelectors'; + +/** + * We want to register new reducers to the extension reducer but only if + * that extension is enabled + */ +export const SET_EXTENSION_REDUCER_ENABLED = 'DASHBOARD/EXTENSIONS/SET_EXTENSION_REDUCER_ENABLED'; +export const setExtensionReducerEnabled = (name: string, enabled: boolean) => ({ + type: SET_EXTENSION_REDUCER_ENABLED, + payload: { name, enabled }, +}); + +export const setSessionStoragePrepopulationReportFunction = (reportId, extensionName) => + setSessionStorageValue(getPrepopulationReportExtensionSessionStorageKey(reportId), extensionName); + +export const deleteSessionStoragePrepopulationReportFunction = (reportId) => + deleteSessionStorageValue(getPrepopulationReportExtensionSessionStorageKey(reportId)); diff --git a/src/extensions/state/ExtensionReducer.ts b/src/extensions/state/ExtensionReducer.ts new file mode 100644 index 000000000..96639fa8e --- /dev/null +++ b/src/extensions/state/ExtensionReducer.ts @@ -0,0 +1,50 @@ +import { EXTENSIONS_REDUCERS } from '../ExtensionConfig'; +import { SET_EXTENSION_REDUCER_ENABLED } from './ExtensionActions'; + +export const INITIAL_EXTENSIONS_STATE = { + active: true, + activeReducers: [], +}; + +const update = (state, mutations) => Object.assign({}, state, mutations); + +export const extensionsReducer = (state = INITIAL_EXTENSIONS_STATE, action: { type: any; payload: any }) => { + const { type, payload } = action; + + if (!action.type.startsWith('DASHBOARD/EXTENSIONS')) { + return state; + } + + // Checking if we are receiving an action from an enabled extension + if (state.activeReducers && state.activeReducers.some((prefix) => type.startsWith(prefix))) { + let currentPrefix = state.activeReducers.find((prefix) => type.startsWith(prefix)); + let { name, reducer } = EXTENSIONS_REDUCERS[currentPrefix]; + let newState = { + ...state, + }; + newState[name] = reducer(state[name], action); + return newState; + } + + switch (type) { + case SET_EXTENSION_REDUCER_ENABLED: { + const { name, enabled } = payload; + const newState = { + ...state, + }; + if (enabled) { + newState.activeReducers.push(name); + } else { + const index = newState.activeReducers.indexOf(name); + if (index > -1) { + // only splice array when item is found + newState.activeReducers.splice(index, 1); // 2nd parameter means remove one item only + } + } + return newState; + } + default: { + return state; + } + } +}; diff --git a/src/extensions/state/ExtensionSelectors.ts b/src/extensions/state/ExtensionSelectors.ts new file mode 100644 index 000000000..7d7f5e38a --- /dev/null +++ b/src/extensions/state/ExtensionSelectors.ts @@ -0,0 +1,21 @@ +import { getSessionStorageValue } from '../../sessionStorage/SessionStorageSelectors'; + +export const getPrepopulationReportExtensionSessionStorageKey = (cardId) => `prepopulation_report_extension__${cardId}`; + +/** + * An Extension can define a function to run before (prepopulate) the report itself + * @param state State of the application + * @param cardId Unique Id of the card running the report + * @returns Name of the Extension to use to fetch the prepopulation function + */ +export const getPrepopulateReportExtension = (state: any, cardId: string) => { + return getSessionStorageValue(state, getPrepopulationReportExtensionSessionStorageKey(cardId)); +}; +export const getExtensionActiveReducers = (state: any) => { + return state.dashboard.extensions && state.dashboard.extensions.activeReducers; +}; + +export const getExtensionSettings = (state: any, name: string) => { + let res = state.dashboard.extensions && state.dashboard.extensions[name]; + return res != undefined && res.settings ? res.settings : {}; +}; diff --git a/src/extensions/styling/StyleRuleCreationModal.tsx b/src/extensions/styling/StyleRuleCreationModal.tsx index f37bc5a34..437146182 100644 --- a/src/extensions/styling/StyleRuleCreationModal.tsx +++ b/src/extensions/styling/StyleRuleCreationModal.tsx @@ -1,15 +1,14 @@ import React, { useEffect } from 'react'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import CloseIcon from '@material-ui/icons/Close'; -import Badge from '@material-ui/core/Badge'; -import { Button, Fab, MenuItem, TextField, Typography } from '@material-ui/core'; +import { Autocomplete, TextField, MenuItem } from '@mui/material'; import NeoColorPicker from '../../component/field/ColorPicker'; -import AddIcon from '@material-ui/icons/Add'; -import TuneIcon from '@material-ui/icons/Tune'; -import { Autocomplete } from '@material-ui/lab'; +import { IconButton, Button, Dialog, Dropdown, TextInput } from '@neo4j-ndl/react'; +import { + AdjustmentsHorizontalIconOutline, + XMarkIconOutline, + PlusIconOutline, + PlayIconSolid, +} from '@neo4j-ndl/react/icons'; +import { withStyles } from '@mui/styles'; // The set of conditional checks that are included in the rule specification. const RULE_CONDITIONS = [ @@ -187,230 +186,193 @@ export const NeoCustomReportStyleModal = ({
{customReportStyleModalOpen ? ( - - + + Rule-Based Styling - - - - - - -
- -

- You can define rule-based styling for the report here.
- Style rules are checked in-order and override the default behaviour - if no rules are valid, no style is - applied. -
- {type == 'graph' || type == 'map' ? ( -

- For {type} reports, the field name should be specified in the format label.name, - for example: Person.age. This is case-sensentive. -

- ) : ( - <> - )} - {type == 'line' || type == 'value' || type == 'bar' || type == 'pie' || type == 'table' ? ( -

- For {type} reports, the field name should be the exact name of the returned field.
- For example, if your query is MATCH (n:Movie) RETURN n.rating as Rating, your field - name is Rating. -

- ) : ( - <> - )} -

-
-
+ + +

+ You can define rule-based styling for the report here.
+ Style rules are checked in-order and override the default behaviour - if no rules are valid, no style is + applied. +
+ {type == 'graph' || type == 'map' ? ( +

+ For {type} reports, the field name should be specified in the format label.name, + for example: Person.age. This is case-sensitive. +

+ ) : ( + <> + )} + {type == 'line' || type == 'value' || type == 'bar' || type == 'pie' || type == 'table' ? ( +

+ For {type} reports, the field name should be the exact name of the returned field.
+ For example, if your query is MATCH (n:Movie) RETURN n.rating as Rating, your field name + is Rating. +

+ ) : ( + <> + )} +

+
+
- +
+ {rules.map((rule, index) => { + const ruleType = RULE_BASED_REPORT_CUSTOMIZATIONS[type].find( + (el) => el.value === rule.customization + ); return ( - <> - - - -
-
+ + - - + fluid + > + - -
-
- + - + - - - + + + ); })} - -
- {index + 1}. - - IF - + + {index + 1}. + + IF + +
+ + e.toLowerCase().includes(rule.field.toLowerCase()) + )} + value={rule.field ? rule.field : ''} + inputValue={rule.field ? rule.field : ''} + popupIcon={<>} + style={{ display: 'inline-block', width: '38%' }} + onInputChange={(event, value) => { + updateRuleField(index, 'field', value); + }} + onChange={(event, newValue) => { + updateRuleField(index, 'field', newValue); }} - > - - e.toLowerCase().includes(rule.field.toLowerCase()) - )} - value={rule.field ? rule.field : ''} - inputValue={rule.field ? rule.field : ''} - popupIcon={<>} - style={{ display: 'inline-block', width: 185, marginLeft: '5px', marginTop: '5px' }} - onInputChange={(event, value) => { - updateRuleField(index, 'field', value); - }} - onChange={(event, newValue) => { - updateRuleField(index, 'field', newValue); - }} - renderInput={(params) => ( - - )} - /> -
- updateRuleField(index, 'condition', e.target.value)} - > - {RULE_CONDITIONS.map((option) => ( - - {option.label} - - ))} - - - ( + + )} + /> + updateRuleField(index, 'condition', newValue.value), + options: RULE_CONDITIONS.map((option) => ({ + label: option.label, + value: option.value, + })), + value: { label: rule.condition, value: rule.condition }, + }} + style={{ marginLeft: '1%', width: '20%', display: 'inline-block' }} + fluid + /> +
+ updateRuleField(index, 'value', e.target.value)} - > -
- THEN - - updateRuleField(index, 'customization', e.target.value)} - > - {RULE_BASED_REPORT_CUSTOMIZATIONS[type] && - RULE_BASED_REPORT_CUSTOMIZATIONS[type].map((option) => ( - - {option.label} - - ))} - - + + THEN + +
+ updateRuleField(index, 'customization', newValue.value), + options: RULE_BASED_REPORT_CUSTOMIZATIONS[type].map((option) => ({ + label: option.label, + value: option.value, + })), + value: { + label: ruleType ? ruleType.label : '', + value: rule.customization, + }, }} - > - -
+ style={{ width: '40%', display: 'inline-block' }} + fluid + /> +
+ +
+
updateRuleField(index, 'customizationValue', value)} > -
- { - setRules([...rules.slice(0, index), ...rules.slice(index + 1)]); - }} - > - - -
+ { + setRules([...rules.slice(0, index), ...rules.slice(index + 1)]); + }} + > + + +
- - +
+ { const newRule = getDefaultRule(RULE_BASED_REPORT_CUSTOMIZATIONS[type][0].value); setRules(rules.concat(newRule)); }} > - - - + + +
- -
-
- - - -
+ + +
+ + + +
) : ( <> @@ -419,4 +381,4 @@ export const NeoCustomReportStyleModal = ({ ); }; -export default NeoCustomReportStyleModal; +export default withStyles({})(NeoCustomReportStyleModal); diff --git a/src/extensions/styling/StyleRuleEvaluator.ts b/src/extensions/styling/StyleRuleEvaluator.ts index c225cde52..c8dd7da9c 100644 --- a/src/extensions/styling/StyleRuleEvaluator.ts +++ b/src/extensions/styling/StyleRuleEvaluator.ts @@ -1,4 +1,4 @@ -import { makeStyles } from '@material-ui/styles'; +import { makeStyles } from '@mui/styles'; import { extensionEnabled } from '../ExtensionUtils'; import React, { useEffect } from 'react'; @@ -148,7 +148,7 @@ const evaluateCondition = (realValue, condition, ruleValue) => { }; /** - * Uses the material-ui `makeStyles` functionality to generate classes for each of the rules. + * Uses the mui `makeStyles` functionality to generate classes for each of the rules. * This is used for styling table rows and columns. */ export const generateClassDefinitionsBasedOnRules = (rules) => { diff --git a/src/extensions/workflows/component/Icons.tsx b/src/extensions/workflows/component/Icons.tsx new file mode 100644 index 000000000..4dac26018 --- /dev/null +++ b/src/extensions/workflows/component/Icons.tsx @@ -0,0 +1,85 @@ +import React from 'react'; +import TimerIcon from '@mui/icons-material/Timer'; +import CheckCircleIcon from '@mui/icons-material/CheckCircle'; +import LoopIcon from '@mui/icons-material/Loop'; +import CancelIcon from '@mui/icons-material/Cancel'; +import PanToolIcon from '@mui/icons-material/PanTool'; +import { Tooltip } from '@mui/material'; + +export const getStoppingIcon = (flipped) => { + return ( + + + + ); +}; +export const getCompleteIcon = (flipped) => { + return ( + + + + ); +}; + +export const getRunningIcon = () => { + return ( + + + + ); +}; + +export const getWaitingIcon = (flipped) => { + return ( + + + + ); +}; + +export const getCancelledIcon = (flipped) => { + return ( + + + + ); +}; + +export const getErrorIcon = (flipped) => { + return ( + + + + ); +}; diff --git a/src/extensions/workflows/component/WorkflowDrawerButton.tsx b/src/extensions/workflows/component/WorkflowDrawerButton.tsx new file mode 100644 index 000000000..57f012fec --- /dev/null +++ b/src/extensions/workflows/component/WorkflowDrawerButton.tsx @@ -0,0 +1,159 @@ +import React, { useContext, useEffect } from 'react'; +import { connect } from 'react-redux'; +import NeoWorkflowListModal from './WorkflowListModal'; +import SlowMotionVideoIcon from '@mui/icons-material/SlowMotionVideo'; +import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; +import { runWorkflow } from '../util/WorkflowRunner'; +import { getWorkflowsList } from '../state/WorkflowSelectors'; +import { updateWorkflowStepStatus } from '../state/WorkflowActions'; +import { STEP_STATUS } from './WorkflowRunnerModal'; +import { loadDatabaseListFromNeo4jThunk } from '../../../dashboard/DashboardThunks'; +import { getDatabase, getGlobalParameters } from '../../../settings/SettingsSelectors'; +import { ListItem, ListItemIcon, ListItemText } from '@mui/material'; + +/** + * Component that has the responsiblity to run Cypher workflows. + * The component will run the workflow in background, so we can continue + * to use the application while the workflow runs. The button will change color based on + * the status of the current workflow + * @param workflows List of currently defined workflows stored in the state + * @param updateWorkflowStepStatus Action to change the status of a step + */ +const NeoWorkflowDrawerButton = ({ + workflows, + database, + parameters, + updateWorkflowStepStatus, + loadDatabaseListFromNeo4j, +}) => { + const [open, setOpen] = React.useState(false); + const [isRunning, setIsRunning] = React.useState(false); + // For each step of the current workflow, it's status + const [workflowStepStatus, setWorkflowStepStatus] = React.useState([]); + const [runnerModalIsOpen, setRunnerModalIsOpen] = React.useState(false); + const [results, setResults] = React.useState([]); + // Object that contains the information regarding the current run + const [currentRun, setCurrentRun] = React.useState({}); + const [currentRunIndex, setCurrentRunIndex] = React.useState(-1); + // Number that represent the status of the workflow (managed by the workflow runner) + const [currentWorkflowStatus, setCurrentWorkflowStatus] = React.useState(-1); + + // Runner to we can increase to trigger a workflow run + const [runCounter, setRunCounter] = React.useState(0); + + function increaseRunCounter() { + setRunCounter(runCounter + 1); + } + // Database that will run the workflow (by default the one specified at connection time) + const [workflowDatabase, setWorkflowDatabase] = React.useState(database); + const [databaseList, setDatabaseList] = React.useState([]); + + const { driver } = useContext(Neo4jContext); + + /** + * Defines the color representing the status of the workflow runner + * - blue : currently running a workflow + * - gray : first initialization value or stopped workflow + * - green: completed with success + * - red: stopped because of an error + * @returns A string representing an HTML color + */ + const getButtonColor = () => { + const colors = {}; + colors[STEP_STATUS.CANCELLED] = 'gray'; + colors[STEP_STATUS.ERROR] = 'red'; + colors[STEP_STATUS.COMPLETE] = 'green'; + + return isRunning ? 'blue' : colors[currentWorkflowStatus] ? colors[currentWorkflowStatus] : 'gray'; + }; + + // Effect to load the list of database when opening the list of workflows + useEffect(() => { + loadDatabaseListFromNeo4j(driver, (result) => { + let sysIndex = result.indexOf('system'); + if (sysIndex > -1) { + // only splice array when item is found + result.splice(sysIndex, 1); // 2nd parameter means remove one item only + } + setDatabaseList(result); + }); + }, [open]); + + // Effect to trigger a workflow run + useEffect(() => { + if (currentRunIndex >= 0 && !isRunning) { + // Getting the workflow to run from the list of existing workflows + let workflow = workflows[currentRunIndex]; + + // Keeping the fact that is running, to block some buttons on the UI + setIsRunning(true); + + // Inside the run now there is the object to stop it (now it will only stop after the end of a step, we need to understand how to stop completely) + let run = runWorkflow( + driver, + workflow, + parameters, + workflowDatabase, + currentRunIndex, + workflowStepStatus, + setWorkflowStepStatus, + setResults, + setIsRunning, + setCurrentWorkflowStatus, + updateWorkflowStepStatus + ); + setCurrentRun(run); + } + }, [runCounter]); + + // Button that will show in the Drawer + const button = ( +
+ setOpen(true)} id='workflows-sidebar-button'> + + + + + +
+ ); + return ( + <> + {button} + {open ? ( + + ) : ( + <> + )} + + ); +}; + +const mapStateToProps = (state) => ({ + workflows: getWorkflowsList(state), + parameters: getGlobalParameters(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + updateWorkflowStepStatus: (index, stepIndex, status) => dispatch(updateWorkflowStepStatus(index, stepIndex, status)), + loadDatabaseListFromNeo4j: (driver, callback) => dispatch(loadDatabaseListFromNeo4jThunk(driver, callback)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(NeoWorkflowDrawerButton); diff --git a/src/extensions/workflows/component/WorkflowEditorModal.tsx b/src/extensions/workflows/component/WorkflowEditorModal.tsx new file mode 100644 index 000000000..310913881 --- /dev/null +++ b/src/extensions/workflows/component/WorkflowEditorModal.tsx @@ -0,0 +1,270 @@ +import React, { useEffect } from 'react'; +import AddIcon from '@mui/icons-material/Add'; +import DeleteIcon from '@mui/icons-material/Delete'; +import DragIndicatorIcon from '@mui/icons-material/DragIndicator'; +import PlaylistPlayIcon from '@mui/icons-material/PlaylistPlay'; +import SaveIcon from '@mui/icons-material/Save'; +import RGL, { WidthProvider } from 'react-grid-layout'; +import { NeoWorkflowStepEditorModal } from './WorkflowStepEditorModal'; +import { connect } from 'react-redux'; +import { getWorkflow } from '../state/WorkflowSelectors'; +import { createWorkflow, updateWorkflowName, updateWorkflowSteps } from '../state/WorkflowActions'; +import { Button, Dialog, DialogContent, DialogTitle, Fab, IconButton, TextField, Typography } from '@mui/material'; +const ReactGridLayout = WidthProvider(RGL); + +function moveElementInArray(array, fromIndex, toIndex) { + array.splice(toIndex, 0, array.splice(fromIndex, 1)[0]); +} + +/** + * The pop-up window used to create and edit workflows. + */ +export const NeoWorkflowEditorModal = ({ + open, + setOpen, + index, + workflow, + createWorkflow, + updateWorkflowSteps, + updateWorkflowName, +}) => { + const placeholderName = `My Workflow #${index + 1}`; + const [steps, setSteps] = React.useState(workflow.steps ? workflow.steps : []); + const [name, setName] = React.useState(workflow.name ? workflow.name : placeholderName); + const [currentStep, setCurrentStep] = React.useState({ name: '', query: '' }); + const [currentIndex, setCurrentIndex] = React.useState(-1); + + useEffect(() => { + setName(workflow.name ? workflow.name : placeholderName); + setSteps(workflow.steps ? workflow.steps : []); + }, [index]); + + const handleSave = () => { + if (Object.keys(workflow).length > 0) { + updateWorkflowSteps(index, steps); + updateWorkflowName(index, name); + } else { + createWorkflow(name, steps); + } + setOpen(false); + }; + + const addEmptyStep = () => { + const step = { name: `Step #${steps.length + 1}`, query: '' }; + setCurrentStep(step); + setCurrentIndex(steps.length); + setSteps(steps.concat(step)); + }; + + const updateStep = (stepIndex, name, query) => { + let tmp = [...steps]; + const step = { name: name, query: query }; + if (query) { + tmp[stepIndex] = step; + } else { + tmp.splice(stepIndex, 1); + } + setSteps(tmp); + setCurrentIndex(-1); + }; + + const [addStepModalOpen, setAddStepModalOpen] = React.useState(false); + + const layout = { + ...steps.map((step, index) => { + return { x: 0, y: index, i: index + step.name, w: 6, h: 1 }; + }), + }; + return ( +
+ {open ? ( + + + + + + + + + + + +
+ + + { + setName(event.target.value); + }} + /> + + + + +
+
+
+ +

+ You can define a workflow here. A workflow consists of one or more steps that together create an + analytical pipeline. +

+
+
+ { + // inside the steps array, move the entry at index 'oldIndex' to 'newIndex'. + // TODO - this has a small delay when updating the layout somehow. + const oldIndex = oldPosition.y; + const newIndex = newPosition.y; + const newSteps = [...steps]; + moveElementInArray(newSteps, oldIndex, newIndex); + setSteps(newSteps); + }} + rowHeight={50} + compactType={'vertical'} + > + {steps.map((step, i) => ( +
+ + + + + + +
+ + + + + { + const newSteps = [...steps]; + newSteps.splice(i, 1); + setSteps(newSteps); + }} + style={{ float: 'right' }} + > + + +
+
+ ))} +
+ + + { + addEmptyStep(); + setAddStepModalOpen(true); + }} + > + + + +
+
+
+
+ ) : ( + <> + )} + + {addStepModalOpen ? ( + + ) : ( + <> + )} +
+ ); +}; + +const mapStateToProps = (state, ownProps) => ({ + workflow: getWorkflow(state, ownProps.index), +}); + +const mapDispatchToProps = (dispatch) => ({ + createWorkflow: (name, steps) => { + dispatch(createWorkflow(name, steps)); + }, + updateWorkflowSteps: (index, steps) => { + dispatch(updateWorkflowSteps(index, steps)); + }, + updateWorkflowName: (index, name) => { + dispatch(updateWorkflowName(index, name)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(NeoWorkflowEditorModal); diff --git a/src/extensions/workflows/component/WorkflowListModal.tsx b/src/extensions/workflows/component/WorkflowListModal.tsx new file mode 100644 index 000000000..a24d568b5 --- /dev/null +++ b/src/extensions/workflows/component/WorkflowListModal.tsx @@ -0,0 +1,279 @@ +import React, { useEffect } from 'react'; + +import { withStyles } from '@mui/styles'; +import { connect } from 'react-redux'; +import NeoWorkflowEditorModal from './WorkflowEditorModal'; +import { PlayArrow, Stop } from '@mui/icons-material'; +import DeleteIcon from '@mui/icons-material/Delete'; +import EditIcon from '@mui/icons-material/Edit'; +import CloseIcon from '@mui/icons-material/Close'; +import StopIcon from '@mui/icons-material/Stop'; +import { DataGrid, gridClasses } from '@mui/x-data-grid'; +import NeoWorkflowRunnerModal, { STEP_STATUS } from './WorkflowRunnerModal'; +import { getWorkflowsList } from '../state/WorkflowSelectors'; +import { deleteWorkflow } from '../state/WorkflowActions'; +import NeoField from '../../../component/field/Field'; +import { getCancelledIcon, getCompleteIcon, getRunningIcon, getErrorIcon, getStoppingIcon } from './Icons'; +import { Badge, Button, Dialog, DialogContent, DialogTitle, IconButton, MenuItem } from '@mui/material'; + +/** +* Component that shows the list of workflows. From this modal they can: + - Create a new workflow + - Update an existing workflow + - Delete a workflow + - Run a workflow +* @param open Always set to true when opening the modal +* @param setOpen Callback to close the modal +* @param isRunning True if a workflow is currently running, False otherwise +* @param index Index of the currently selected +* @param setIndex Callback to set the currently selected index +* @param workflowDatabase Database selected to run the workflow +* @param setWorkflowDatabase Callback to set the database that will run the workflow +* @param databaseList List of possible databases +* @param workflowStepStatus List that contains, for each step of the running workflow, it's own status +* @param setWorkflowStepStatus Callback to set the status for each step of the workflow +* @param runnerModalIsOpen True if the runner modal is open, False otherwise +* @param setRunnerModalIsOpen Callback to change the state of runnerModalIsOpen +* @param currentRunIndex Index of the workflow that is currently running +* @param currentWorkflowStatus Status of the total workflow (Completed, Failed, Cancelled) +* @param currentRun Object containing the promise if the run and its abort function +* @param results Results got back from then workflow +* @param workflowsList List of possible workflows, got from the state +* @param deleteWorkflow Dispacth to delete a workflow from the stored list +*/ +export const NeoWorkflowListModal = ({ + open, + setOpen, + isRunning, + workflowDatabase, + setWorkflowDatabase, + databaseList, + workflowStepStatus, + setWorkflowStepStatus, + runnerModalIsOpen, + setRunnerModalIsOpen, + currentRunIndex, + setCurrentRunIndex, + increaseRunCounter, + currentWorkflowStatus, + currentRun, + results, + workflowsList, + deleteWorkflow, +}) => { + function getStatusMessage() { + const messages = {}; + messages[STEP_STATUS.CANCELLED] = getCancelledIcon(false); + messages[STEP_STATUS.ERROR] = getErrorIcon(false); + messages[STEP_STATUS.COMPLETE] = getCompleteIcon(false); + messages[STEP_STATUS.STOPPING] = getStoppingIcon(false); + + return isRunning && currentWorkflowStatus != STEP_STATUS.STOPPING + ? getRunningIcon() + : messages[currentWorkflowStatus] + ? messages[currentWorkflowStatus] + : ''; + } + + function openRunnerModal(index) { + setRunnerModalIsOpen(true); + setIndex(index); + } + + function triggerWorkflowRun(index) { + setWorkflowStepStatus([]); + setCurrentRunIndex(index); + + // Trigger workflow + increaseRunCounter(); + } + const [index, setIndex] = React.useState(currentRunIndex); + + const [editorOpen, setEditorOpen] = React.useState(false); + + // The index of the selected workflow + const [rows, setRows] = React.useState([]); + + // Text to show on the screen the currently selected database + const [databaseText, setDatabaseText] = React.useState(workflowDatabase); + + // TODO: continue binding data to the UI + useEffect(() => { + let tmp = workflowsList.map((workflow, index) => { + return { id: index, name: workflow.name, stepCount: workflow.steps.length }; + }); + setRows(tmp); + }, [JSON.stringify(workflowsList)]); + + const columns = [ + { field: 'id', hide: true, headerName: 'ID', width: 150 }, + { + field: 'name', + headerName: 'Name', + renderCell: (row) => { + // TODO: find a cool way to show the status here + return
{row.formattedValue}
; + }, + width: 210, + }, + { + field: 'status', + headerName: 'Status', + renderCell: (row) => { + // TODO: find a cool way to show the status here + return ( +
openRunnerModal(row.id)}>{row.id === currentRunIndex ? getStatusMessage() : ''}
+ ); + }, + width: 60, + align: 'center', + }, + { field: 'stepCount', headerName: 'Steps', width: 60 }, + { + field: 'actions', + headerName: 'Actions', + renderCell: (row) => { + return ( +
+ { + triggerWorkflowRun(row.id); + }} + disabled={isRunning} + style={{ padding: '6px' }} + > + + + + + { + currentRun.abort('Stopped by UI', true); + }} + disabled={!(isRunning && row.id === currentRunIndex)} + style={{ padding: '6px' }} + > + + + + + { + setEditorOpen(true); + setIndex(row.id); + }} + style={{ padding: '6px' }} + disabled={isRunning && row.id == currentRunIndex} + > + + + + + { + deleteWorkflow(row.id); + }} + style={{ padding: '6px' }} + disabled={isRunning && row.id == currentRunIndex} + > + + + + +
+ ); + }, + width: 160, + }, + ]; + + return ( + <> + { + setOpen(false); + }} + aria-labelledby='form-dialog-title' + > + + Workflows + { + setOpen(false); + }} + style={{ padding: '3px', float: 'right' }} + > + + + + + + +
+ <>, ColumnSortedAscendingIcon: () => <> }} + /> +
+ { + return { label: database, value: database }; + })} + onChange={(value) => { + setDatabaseText(value); + setWorkflowDatabase(value); + }} + /> + +
+
+ {editorOpen ? : <>} + {runnerModalIsOpen ? ( + + ) : ( + <> + )} + + ); +}; + +const mapStateToProps = (state) => ({ + workflowsList: getWorkflowsList(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + deleteWorkflow: (index) => { + dispatch(deleteWorkflow(index)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(NeoWorkflowListModal); diff --git a/src/extensions/workflows/component/WorkflowRunnerModal.tsx b/src/extensions/workflows/component/WorkflowRunnerModal.tsx new file mode 100644 index 000000000..74a332948 --- /dev/null +++ b/src/extensions/workflows/component/WorkflowRunnerModal.tsx @@ -0,0 +1,151 @@ +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import { withStyles } from '@mui/styles'; +import Accordion from '@mui/material/Accordion'; +import AccordionSummary from '@mui/material/AccordionSummary'; +import AccordionDetails from '@mui/material/AccordionDetails'; +import Typography from '@mui/material/Typography'; +import CloseIcon from '@mui/icons-material/Close'; +import { getWorkflow } from '../state/WorkflowSelectors'; +import { getCancelledIcon, getCompleteIcon, getRunningIcon, getErrorIcon, getWaitingIcon } from './Icons'; +import NeoWorkflowRunnerStepDetails from './WorkflowRunnerStepDetails'; +import { Badge, Dialog, DialogContent, DialogContentText, DialogTitle, IconButton } from '@mui/material'; + +const NeoAccordion = withStyles({ + root: { + border: '1px solid rgba(0, 0, 0, .1)', + boxShadow: 'none', + '&:not(:last-child)': { + borderBottom: 0, + }, + '&:before': { + display: 'none', + }, + '&$expanded': { + margin: 'auto', + }, + }, + expanded: {}, +})(Accordion); + +const NeoAccordionSummary = withStyles({ + root: { + backgroundColor: 'rgba(0, 0, 0, .03)', + borderBottom: '1px solid rgba(0, 0, 0, .125)', + marginBottom: -1, + minHeight: 56, + '&$expanded': { + minHeight: 56, + }, + }, + content: { + '&$expanded': { + margin: '12px 0', + }, + }, + expanded: {}, +})(AccordionSummary); + +const NeoAccordionDetails = withStyles((theme) => ({ + root: { + padding: theme.spacing(2), + }, +}))(AccordionDetails); + +const styles = {}; + +export enum STEP_STATUS { + WAITING, + RUNNING, + ERROR, + COMPLETE, + CANCELLED, + STOPPING, +} + +export const NeoWorkflowRunnerModal = ({ open, setOpen, _index, workflowStepStatus, results, workflow }) => { + const [expanded, setExpanded] = React.useState(undefined); + + const handleChange = (panel: string) => (event: React.ChangeEvent, newExpanded: boolean) => { + setExpanded(newExpanded ? panel : undefined); + }; + + const getExpandIcon = (index, item, expanded) => { + if (workflowStepStatus[index] == STEP_STATUS.COMPLETE) { + return getCompleteIcon(item == expanded); + } + if (workflowStepStatus[index] == STEP_STATUS.RUNNING) { + return getRunningIcon(); + } + if (workflowStepStatus[index] == STEP_STATUS.ERROR) { + return getErrorIcon(item == expanded); + } + if (workflowStepStatus[index] == STEP_STATUS.CANCELLED) { + return getCancelledIcon(item == expanded); + } + return getWaitingIcon(item == expanded); + }; + + function handleClose() { + setOpen(false); + } + + return ( + { + handleClose(); + }} + aria-labelledby='form-dialog-title' + > + + Running '{workflow.name}' + { + handleClose(); + }} + style={{ padding: '3px', float: 'right' }} + > + + + + + + + +
+ {workflow.steps && + workflow.steps.map((step, index) => { + return ( + + + {step.name} + + + + + + ); + })} +
+
+
+
+ ); +}; +const mapStateToProps = (state, ownProps) => ({ + workflow: getWorkflow(state, ownProps.index), +}); + +const mapDispatchToProps = () => ({}); + +export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(NeoWorkflowRunnerModal)); diff --git a/src/extensions/workflows/component/WorkflowRunnerStepDetails.tsx b/src/extensions/workflows/component/WorkflowRunnerStepDetails.tsx new file mode 100644 index 000000000..c3fbfffd7 --- /dev/null +++ b/src/extensions/workflows/component/WorkflowRunnerStepDetails.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { REPORT_TYPES } from '../../../config/ReportConfig'; +import NeoCodeViewerComponent from '../../../component/editor/CodeViewerComponent'; +import { STEP_STATUS } from './WorkflowRunnerModal'; +import { Button, TextareaAutosize } from '@mui/material'; + +enum views { + QUERY, + DATA, +} + +const NeoWorkflowRunnerStepDetails = ({ step, records, status }) => { + const [view, setView] = React.useState(views.QUERY); + const Chart = REPORT_TYPES.table.component; + return ( +
+
+ + +
+
+ {view == views.QUERY ? ( + + ) : ( + <> + )} + + {view == views.DATA ? ( +
+ {status == STEP_STATUS.ERROR ? ( + + ) : ( + + )} +
+ ) : ( + <> + )} +
+
+ ); +}; + +export default NeoWorkflowRunnerStepDetails; diff --git a/src/extensions/workflows/component/WorkflowStepEditorModal.tsx b/src/extensions/workflows/component/WorkflowStepEditorModal.tsx new file mode 100644 index 000000000..c19eb40a9 --- /dev/null +++ b/src/extensions/workflows/component/WorkflowStepEditorModal.tsx @@ -0,0 +1,95 @@ +import React, { useEffect } from 'react'; +import { connect } from 'react-redux'; +import NeoCodeEditorComponent from '../../../component/editor/CodeEditorComponent'; +import { Badge, Dialog, DialogContent, DialogTitle, IconButton, TextField } from '@mui/material'; +import PlaylistPlayIcon from '@mui/icons-material/PlaylistPlay'; +import SaveIcon from '@mui/icons-material/Save'; +import { withStyles } from '@mui/styles'; + +const styles = {}; +export const NeoWorkflowStepEditorModal = ({ index, stepName, query, open, setOpen, updateStep }) => { + const [name, setName] = React.useState(stepName); + const [queryText, setQueryText] = React.useState(query); + const handleClose = () => { + updateStep(index, name, queryText); + setOpen(false); + }; + + useEffect(() => { + setName(stepName); + setQueryText(query); + }, [index]); + + return ( + + + + + + + + + + + +
+ + + { + setName(event.target.value); + }} + /> + + + + + + +
+
+ + + { + setQueryText(value); + }} + placeholder={'Enter Cypher here...\n'} + /> +

+ {'Write the query here that will be used during this step of the workflow.'} +

+
+
+ ); +}; +const mapStateToProps = () => ({}); +const mapDispatchToProps = () => ({}); +export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(NeoWorkflowStepEditorModal)); diff --git a/src/extensions/workflows/state/WorkflowActions.ts b/src/extensions/workflows/state/WorkflowActions.ts new file mode 100644 index 000000000..354a8468e --- /dev/null +++ b/src/extensions/workflows/state/WorkflowActions.ts @@ -0,0 +1,57 @@ +export const WORKFLOWS_ACTION_PREFIX = 'DASHBOARD/EXTENSIONS/WORKFLOWS/'; + +export const CREATE_WORKFLOW = `${WORKFLOWS_ACTION_PREFIX}CREATE_WORKFLOW`; +/** + * A workflow is defined by a name and a series of steps (a step is a Cypher Query for now) and its + * index in the list of workflows + * @param workflowName name of the workflow + * @param steps the steps in the workflow + */ +export const createWorkflow = (workflowName, steps) => ({ + type: CREATE_WORKFLOW, + // TODO: Simplify naming in the payload for all extension actions. + payload: { workflowName, steps }, +}); + +export const SET_WORKFLOW_STEPS = `${WORKFLOWS_ACTION_PREFIX}SET_WORKFLOW_STEPS`; +/** + * A workflow is defined by a name and a series of steps (a step is a Cypher Query for now) + * @param index index of the workflow + * @param steps the steps in the workflow + */ +export const updateWorkflowSteps = (index, steps) => ({ + type: SET_WORKFLOW_STEPS, + // TODO: Simplify naming in the payload for all extension actions. + payload: { index, steps }, +}); + +export const UPDATE_WORKFLOW_NAME = `${WORKFLOWS_ACTION_PREFIX}UPDATE_WORKFLOW_NAME`; +/** + * Action to change the name of an existing workflow + * @param index index of the workflow + * @param newWorkflowName New name of the workflow + */ +export const updateWorkflowName = (index, newWorkflowName) => ({ + type: UPDATE_WORKFLOW_NAME, + // TODO: Simplify naming in the payload for all extension actions. + payload: { index, newWorkflowName }, +}); + +export const UPDATE_WORKFLOW_STEP_STATUS = `${WORKFLOWS_ACTION_PREFIX}UPDATE_WORKFLOW_STEP_STATUS`; +/** + * Action to change the status of a step inside a specified workflow + * @param index Current name of the workflow + * @param stepIndex New name of the workflow + * @param status Status of the step, can be in [FAILED, DONE, RUNNING, PENDING, CANCELLED] + */ +export const updateWorkflowStepStatus = (index, stepIndex, status) => ({ + type: UPDATE_WORKFLOW_STEP_STATUS, + payload: { index, stepIndex, status }, +}); + +export const DELETE_WORKFLOW = `${WORKFLOWS_ACTION_PREFIX}DELETE_WORKFLOW`; +export const deleteWorkflow = (index) => ({ + type: DELETE_WORKFLOW, + // TODO: Simplify naming in the payload for all extension actions. + payload: { index }, +}); diff --git a/src/extensions/workflows/state/WorkflowReducer.ts b/src/extensions/workflows/state/WorkflowReducer.ts new file mode 100644 index 000000000..50a73f6fc --- /dev/null +++ b/src/extensions/workflows/state/WorkflowReducer.ts @@ -0,0 +1,73 @@ +/** + * Reducers define changes to the application state when a given action + */ + +import { + SET_WORKFLOW_STEPS, + DELETE_WORKFLOW, + UPDATE_WORKFLOW_NAME, + CREATE_WORKFLOW, + UPDATE_WORKFLOW_STEP_STATUS, +} from './WorkflowActions'; + +export const initialState = { + workflowsList: [], + settings: {}, +}; + +const update = (state, mutations) => Object.assign({}, state, mutations); + +export const workflowReducer = (state = initialState, action: { type: any; payload: any }) => { + const { type, payload } = action; + + switch (type) { + case CREATE_WORKFLOW: { + const { workflowName, steps } = payload; + let newState = { + ...state, + }; + let workflow = { name: workflowName, steps: steps, createdAt: Date.now() }; + newState.workflowsList.push(workflow); + return newState; + } + case SET_WORKFLOW_STEPS: { + const { index, steps } = payload; + let newState = { + ...state, + }; + newState.workflowsList[index].steps = steps; + return newState; + } + case UPDATE_WORKFLOW_NAME: { + const { index, newWorkflowName } = payload; + let newState = { + ...state, + }; + newState.workflowsList[index].name = newWorkflowName; + return newState; + } + case DELETE_WORKFLOW: { + const { index } = payload; + const newWorkflowsList = [...state.workflowsList]; + newWorkflowsList.splice(index, 1); + let newState = { + ...state, + workflowsList: newWorkflowsList, + }; + return newState; + } + case UPDATE_WORKFLOW_STEP_STATUS: { + const { index, stepIndex, status } = payload; + const newWorkflowsList = [...state.workflowsList]; + newWorkflowsList[index].steps[stepIndex].status = status; + let newState = { + ...state, + workflowsList: newWorkflowsList, + }; + return newState; + } + default: { + return state; + } + } +}; diff --git a/src/extensions/workflows/state/WorkflowSelectors.ts b/src/extensions/workflows/state/WorkflowSelectors.ts new file mode 100644 index 000000000..7d96fd1eb --- /dev/null +++ b/src/extensions/workflows/state/WorkflowSelectors.ts @@ -0,0 +1,20 @@ +// TODO - perhaps we can guarantee creation or something... lets think some more to avoid this check. + +export const WORKFLOW_EXTENSION_NAME = 'workflows'; + +export const getWorkflowsList = (state: any) => { + let res = state.dashboard.extensions && state.dashboard.extensions[WORKFLOW_EXTENSION_NAME]; + return res != undefined && res.workflowsList ? res.workflowsList : []; +}; + +export const getWorkflow = (state: any, index) => { + let res = state.dashboard.extensions && state.dashboard.extensions[WORKFLOW_EXTENSION_NAME]; + return res != undefined && res.workflowsList && res.workflowsList[index] ? res.workflowsList[index] : {}; +}; + +export const getWorkflowStep = (state: any, index, stepIndex) => { + let res = state.dashboard.extensions && state.dashboard.extensions[WORKFLOW_EXTENSION_NAME]; + return res != undefined && res.workflowsList && res.workflowsList[index] && res.workflowsList[index].steps[stepIndex] + ? res.workflowsList[index].steps[stepIndex] + : {}; +}; diff --git a/src/extensions/workflows/util/WorkflowRunner.ts b/src/extensions/workflows/util/WorkflowRunner.ts new file mode 100644 index 000000000..b7cecc33f --- /dev/null +++ b/src/extensions/workflows/util/WorkflowRunner.ts @@ -0,0 +1,182 @@ +import { QueryStatus, runCypherQuery } from '../../../report/ReportQueryRunner'; +import { STEP_STATUS } from '../component/WorkflowRunnerModal'; + +async function sleep(msec) { + return new Promise((resolve) => setTimeout(resolve, msec)); +} + +async function consoleLogAsync(message: string, other?: any) { + await new Promise((resolve) => setTimeout(resolve, 0)).then(() => console.info(message, other)); +} + +// TODO: detach runCypherQuery method from here and define another method for the workflows +async function runWorkflowStep(driver, database, query, parameters, setStatus, setRecords) { + await runCypherQuery( + driver, + database, + query, + parameters, + 1000, + setStatus, + setRecords, + (fields) => { + // eslint-disable-next-line no-console + console.log(`Query runner attempted to set fields: ${JSON.stringify(fields)}`); + }, + [], + false, + false, + false, + 1000 + ); +} +/** + * Runs a workflow and sets the state of each step at their ending + * @param driver Neo4j Driver to call the database + * @param database Database that will be impacted by the workflow + * @param workflow Workflow to run, composed by a list of steps + * @param workflowIndex Index that identifies a worlflow in the list of workflows + * @param workflowStepStatus Status of each step of the workflow + * @param setWorkflowStepStatus Callback to set the total status of the workflow inside the component calling the function + * @param setResults Callback to set the results and show them to the UI + * @param setIsRunning Callback to set if the workflow is running + * @param updateWorkflowStepStatus Callback to set the status of the single step in the workflow + */ +export function runWorkflow( + driver, + workflow, + parameters, + workflowDatabase, + workflowIndex, + workflowStepStatus, + setWorkflowStepStatus, + setResults, + setIsRunning, + setCurrentWorkflowStatus, + updateWorkflowStepStatus +) { + // True if we want to stop the workflow, False otherwise + let stop = false; + // True if triggered from the UI, False otherwise + let stoppedByUser = false; + // Message created from the abort function + let errorMessage = ''; + + function setErrorMessage(msg) { + errorMessage = msg; + } + /** + * Function to stop the run of a workflow. + * It will wait the end of the current step to stop the run. + * @param msg Message to show in the console + * @param fromUI True if triggered from the UI, False otherwise + */ + function abort(msg, fromUI = false) { + setErrorMessage(msg); + setCurrentWorkflowStatus(STEP_STATUS.STOPPING); + stop = true; + stoppedByUser = fromUI; + } + + /** + * Function to set the workflow status when it ends. + * A workflow can be: + * - Completed + * - Failed + * - Cancelled + */ + function setWorkflowFinalStatus() { + let finalStatus = -1; + + if (stop && stoppedByUser) { + finalStatus = STEP_STATUS.CANCELLED; + } else if (workflowStepStatus.findIndex((value) => value != STEP_STATUS.COMPLETE) < 0) { + finalStatus = STEP_STATUS.COMPLETE; + } else if (workflowStepStatus.includes(STEP_STATUS.ERROR)) { + finalStatus = STEP_STATUS.ERROR; + } else { + finalStatus = STEP_STATUS.CANCELLED; + } + + setCurrentWorkflowStatus(finalStatus); + } + /** + * Function to manage the ending of a workflow + */ + function handleEnd() { + setIsRunning(false); + setWorkflowFinalStatus(); + } + + /** + * Function that runs the logic of running every step. + */ + async function run() { + const results: any[] = []; + const database = workflowDatabase; + + // Clear results on new run + setResults([]); + + const setWorkflowStatusForStep = (stepIndex, status) => { + workflowStepStatus[stepIndex] = status; + setWorkflowStepStatus([...workflowStepStatus]); + updateWorkflowStepStatus(workflowIndex, stepIndex, status); + }; + + try { + for (let index = 0; index < workflow.steps.length; index++) { + /** + * Function passed to the query runner to set the records got from the UI + * @param records Records got from the query runner + */ + const setRecords = (records) => { + results[index].records = records; + if (records.length === 1 && records[0].error) { + setErrorMessage(records[0].error); + } + }; + + /** + * Function passed to the query runner to set the status got from the UI + * @param records Records got from the query runner + */ + const setStatus = (status) => { + let possiblePositiveStatus = [QueryStatus.NO_DATA, QueryStatus.COMPLETE, QueryStatus.COMPLETE_TRUNCATED]; + let newStatus = STEP_STATUS.COMPLETE; + // if the query is not completed, throw an error and abort to prevent running the next steps + if (!possiblePositiveStatus.includes(status)) { + newStatus = STEP_STATUS.ERROR; + abort('Something wrong happened during the run of the workflow'); + } + results[index].status = newStatus; + setWorkflowStatusForStep(index, newStatus); + }; + + if (stop) { + throw new Error(errorMessage); + } + + setWorkflowStatusForStep(index, STEP_STATUS.RUNNING); + results.push({ records: [], status: STEP_STATUS.RUNNING }); + + let { query } = workflow.steps[index]; + await runWorkflowStep(driver, database, query, parameters, setStatus, setRecords); + + // Refreshing the result state + setResults(results); + + // Added sleep to prevent super fast refresh on UI + await sleep(10); + } + } catch (e) { + await consoleLogAsync('Error while running a workflow:', e); + } finally { + handleEnd(); + } + } + return { + promise: run(), + abort: abort, + }; +} diff --git a/src/index.pcss b/src/index.pcss new file mode 100644 index 000000000..08f532712 --- /dev/null +++ b/src/index.pcss @@ -0,0 +1,70 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* Create CSS class based components */ +/* https://tailwindcss.com/docs/reusing-styles#extracting-classes-with-apply */ +@layer components { + /* Override Mui default z-index */ + .MuiAppBar-root.n-z-20 { + z-index: 20 !important; + } + + /* Utility functions for buttons */ + .btn-icon-sm-r { + @apply n-ml-token-2 n-w-4 n-h-4; + } + .btn-icon-sm-l { + @apply n-mr-token-2 n-w-4 n-h-4; + } + + .btn-icon-base-r { + @apply n-ml-token-3 n-w-6 n-h-6; + } + + .btn-icon-base-l { + @apply n-mr-token-3 n-w-6 n-h-6; + } + + .btn-icon-lg-r { + @apply n-ml-token-4 n-w-8 n-h-8; + } + + .btn-icon-lg-l { + @apply n-mr-token-4 n-w-8 n-h-8; + } + + /* Utility functions for icons */ + .icon-base { + @apply n-w-6 n-h-6; + } + + .icon-inline { + @apply n-inline n-mb-1; + } + + .icon-inline.text-r { + @apply n-mr-token-3; + } + + .icon-inline.text-l { + @apply n-ml-token-3; + } + + /* Make bullet list points in Markdown card view */ + .card-view ul { + @apply n-list-disc n-ml-token-7; + } + + .ndl-dialog.dialog-xl { + max-width: 75%; + } + + .ndl-dialog.dialog-xxl { + max-width: 90%; + } + + .n-bg-dark-neutral-text-weak { + background-color: rgb(196 200 205 / var(--tw-bg-opacity)) !important; + } +} diff --git a/src/index.tsx b/src/index.tsx index 1d4db6f92..8a366006f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,6 +7,25 @@ import { PersistGate } from 'redux-persist/lib/integration/react'; import Application from './application/Application'; import '/node_modules/react-grid-layout/css/styles.css'; import '/node_modules/react-resizable/css/styles.css'; +import './index.pcss'; +import StyleConfig from './config/StyleConfig'; +import * as Sentry from '@sentry/react'; + +Sentry.init({ + dsn: 'https://25edb17cc4c14c8cb726e7ac1ff74e3b@o110884.ingest.sentry.io/4505397810167808', + integrations: [ + new Sentry.BrowserTracing({ + // Set `tracePropagationTargets` to control for which URLs distributed tracing should be enabled + tracePropagationTargets: ['localhost', /^https:\/\/neodash\.graphapp\.io/, /^http:\/\/neodash\.graphapp\.io/], + }), + new Sentry.Replay(), + ], + // Performance Monitoring + tracesSampleRate: 1.0, // Capture 100% of the transactions, reduce in production! + // Session Replay + replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production. + replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur. +}); /** * Set up the NeoDash application and wrap it in the needed providers. @@ -16,6 +35,8 @@ const store = configureStore(); // @ts-ignore - persist state in browser cache. const persister = persistStore(store); +await StyleConfig.getInstance(); + /** Wrap the application in a redux provider / browser cache persistance gate **/ const provider = ( diff --git a/src/modal/AboutModal.tsx b/src/modal/AboutModal.tsx index 704f8f2b8..164d23aa5 100644 --- a/src/modal/AboutModal.tsx +++ b/src/modal/AboutModal.tsx @@ -1,16 +1,10 @@ import React from 'react'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import CloseIcon from '@material-ui/icons/Close'; -import LibraryBooksIcon from '@material-ui/icons/LibraryBooks'; -import Badge from '@material-ui/core/Badge'; -import { Button } from '@material-ui/core'; -import BugReportIcon from '@material-ui/icons/BugReport'; +import { Button, Dialog, TextLink } from '@neo4j-ndl/react'; +import { BookOpenIconOutline, BeakerIconOutline } from '@neo4j-ndl/react/icons'; +import { Section, SectionTitle, SectionContent } from './ModalUtils'; export const NeoAboutModal = ({ open, handleClose, getDebugState }) => { - const version = '2.2.5'; + const version = '2.3.0'; const downloadDebugFile = () => { const element = document.createElement('a'); @@ -25,104 +19,102 @@ export const NeoAboutModal = ({ open, handleClose, getDebugState }) => { return (
- - - About NeoDash - - - - - - - -
- NeoDash is a dashboard builder for the Neo4j graph database. -
- If you can write Cypher queries, you can build a dashboard in minutes. -
-

Core Features

-
    -
  • - An editor to write and execute  - - Cypher - -  queries. -
  • -
  • Use results of your Cypher queries to create tables, bar charts, graph visualizations, and more.
  • -
  • Style your reports, group them together in pages, and add interactivity between reports.
  • -
  • Save and share your dashboards with your friends.
  • -
- No connectors or data pre-processing needed, it works directly with Neo4j! -
-

Getting Started

- You will automatically start with an empty dashboard when starting up NeoDash for this first time. -
- Click the - - ( Documentation) - -  button to see some example queries and visualizations. -
-

Extending NeoDash

- NeoDash is built with React and  - - use-neo4j - - , It uses  - - charts - -  to power some of the visualizations, and  - - openstreetmap - -  for the map view. -
- You can also extend NeoDash with your own visualizations. Check out the developer guide in the  - - project repository - - .
-

Contact

- For suggestions, feature requests and other feedback: create an issue on the  - GitHub repository, or the  - - Neo4j Community Forums - - . -
-
-
- - - - - -
- - - v{version} -
+ + About NeoDash + +
+
+ + NeoDash is a dashboard builder for the Neo4j graph database. With NeoDash, all you need to do is write + Cypher queries, and you can build a dashboard in minutes. + +
+
+ Core Features + +
    +
  • + An editor to write and execute  + + Cypher + +  queries. +
  • +
  • + Use results of your Cypher queries to create tables, bar charts, graph visualizations, and more. +
  • +
  • Style your reports, group them together in pages, and add interactivity between reports.
  • +
  • Save and share your dashboards with your friends.
  • +
+ No connectors or data pre-processing needed, it works directly with Neo4j! +
+
+
+ Getting Started + + You will automatically start with an empty dashboard when starting up NeoDash for this first time. +
+ Click the{' '} + + ( Documentation) + +  button to see some example queries and visualizations. +
+
+
+ Extending NeoDash + + NeoDash is built with React and  + + use-neo4j + + , It uses{' '} + + charts + {' '} + to power some of the visualizations, and  + + openstreetmap + {' '} + for the map view. You can also extend NeoDash with your own visualizations. Check out the developer + guide in the{' '} + + project repository + + . + +
+
+ Contact + + For suggestions, feature requests and other feedback: create an issue on the  + + GitHub repository + {' '} + , or the{' '} + + Neo4j Community Forums + + . + +
- +
+
+ +
+
+ v{version} +
+
+
); diff --git a/src/modal/ConnectionModal.tsx b/src/modal/ConnectionModal.tsx index 9889d509d..e89614c0f 100644 --- a/src/modal/ConnectionModal.tsx +++ b/src/modal/ConnectionModal.tsx @@ -1,20 +1,7 @@ import React, { useEffect } from 'react'; -import Button from '@material-ui/core/Button'; -import TextField from '@material-ui/core/TextField'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import Badge from '@material-ui/core/Badge'; -import PlayArrow from '@material-ui/icons/PlayArrow'; -import { FormControlLabel, MenuItem, Switch, Tooltip } from '@material-ui/core'; -import SecurityIcon from '@material-ui/icons/Security'; -import WarningIcon from '@material-ui/icons/Warning'; import { SSOLoginButton } from '../component/sso/SSOLoginButton'; -import { CUSTOM_CONNECTION_FOOTER_TEXT } from '../config/ApplicationConfig'; - +import { Button, Dialog, Switch, TextInput, Dropdown, TextLink } from '@neo4j-ndl/react'; +import { PlayIconOutline } from '@neo4j-ndl/react/icons'; /** * Configures setting the current Neo4j database connection for the dashboard. */ @@ -26,6 +13,7 @@ export default function NeoConnectionModal({ connection, dismissable = false, createConnection, + setConnectionProperties, onConnectionModalClose, onSSOAttempt, }) { @@ -57,133 +45,108 @@ export default function NeoConnectionModal({ return (
{ dismissable ? onConnectionModalClose() : null; }} aria-labelledby='form-dialog-title' + disableCloseButton > - - {standalone ? 'Connect to Dashboard' : 'Connect to Neo4j'} - - - - - - - - setProtocol(e.target.value)} - style={{ width: '25%' }} - label='Protocol' - placeholder='neo4j://' - type='text' - > - {protocols.map((option) => ( - - {option} - - ))} - - { - // Help the user here a bit by extracting the hostname if they copy paste things in - const input = e.target.value; - const splitted = input.split('://'); - const host = splitted[splitted.length - 1].split(':')[0].split('/')[0]; - setUrl(host); - }} - label='Hostname' - style={{ marginLeft: '2.5%', width: '60%', marginRight: '2.5%' }} - placeholder='localhost' - type='text' - /> - { - if (event.target.value.toString().length == 0) { - setPort(event.target.value); - } else if (!isNaN(event.target.value)) { - setPort(Number(event.target.value)); - } - }} - label='Port' - style={{ width: '10%' }} - placeholder='7687' - type='text' - /> + {standalone ? 'Connect to Dashboard' : 'Connect to Neo4j'} + +
+ newValue && setProtocol(newValue.value), + options: protocols.map((option) => ({ label: option, value: option })), + value: { label: protocol, value: protocol }, + }} + style={{ width: '25%', display: 'inline-block' }} + fluid + /> +
+ { + // Help the user here a bit by extracting the hostname if they copy paste things in + const input = e.target.value; + const splitted = input.split('://'); + const host = splitted[splitted.length - 1].split(':')[0].split('/')[0]; + setUrl(host); + }} + label='Hostname' + placeholder='localhost' + autoFocus + fluid + /> +
+
+ { + if (event.target.value.toString().length == 0) { + setPort(event.target.value); + } else if (!isNaN(event.target.value)) { + setPort(Number(event.target.value)); + } + }} + label='Port' + placeholder='7687' + fluid + /> +
+
{window.location.href.startsWith('https') && !(protocol.endsWith('+s') || protocol.endsWith('+scc')) ? (
You're running NeoDash from a secure (https) webpage. You can't connect to a Neo4j database with an unencrypted protocol. Change the protocol, or use NeoDash using http instead:   - + {window.location.href.replace('https://', 'http://')} - + .
- ) : ( -
- )} - {url == 'localhost' && (protocol.endsWith('+s') || protocol.endsWith('+scc')) ? ( + ) : null} + {url == 'localhost' && (protocol.endsWith('+s') || protocol.endsWith('+scc')) && (
A local host with an encrypted connection will likely not work - try an unencrypted protocol instead.
- ) : ( -
)} {url.endsWith('neo4j.io') && !protocol.endsWith('+s') ? (
Neo4j Aura databases require a neo4j+s protocol. Your current configuration may not work.
- ) : ( -
- )} - setDatabase(e.target.value)} label='Database (optional)' placeholder='neo4j' - type='text' - fullWidth + fluid /> {!ssoVisible ? ( - setUsername(e.target.value)} label='Username' placeholder='neo4j' - type='text' - fullWidth + fluid /> - ) : ( - <> - )} + ) : null}
{ e.preventDefault(); @@ -192,37 +155,40 @@ export default function NeoConnectionModal({ }} > {!ssoVisible ? ( - setPassword(e.target.value)} label='Password' + placeholder='neo4j' type='password' - fullWidth + fluid /> - ) : ( - <> - )} + ) : null} {ssoSettings.ssoEnabled ? ( - setSsoVisible(!ssoVisible)} - name='checked' - color='primary' - /> - } - label='Use SSO' - > +
+ setSsoVisible(!ssoVisible)} + style={{ marginLeft: '5px' }} + /> +
) : ( <> )} {ssoVisible ? ( - + { + // Remember credentials on click + setConnectionProperties(protocol, url, port, database, '', ''); + }} + /> ) : ( )} -
- - - {standalone ? ( - - {standaloneSettings.standaloneDashboardURL === '' ? ( - <> - Sign in to continue. You will be connected to Neo4j, and load a dashboard called - {standaloneSettings.standaloneDashboardName}. - - ) : ( - <> Sign in to continue. You will be connected to Neo4j, and load a dashboard. - )} - - ) : ( - - Enter your Neo4j database credentials to start. Don't have a Neo4j database yet? Create your own - in  - - Neo4j Desktop - - , or try the  - - Neo4j Aura - -  free tier. - - )} - - + + + {standalone ? ( +
+ {standaloneSettings.standaloneDashboardURL === '' ? ( + <> + Sign in to continue. You will be connected to Neo4j, and load a dashboard called + {standaloneSettings.standaloneDashboardName}. + + ) : ( + <> Sign in to continue. You will be connected to Neo4j, and load a dashboard. + )} +
+ ) : ( +
+ Enter your Neo4j database credentials to start. Don't have a Neo4j database yet? Create your own in  + + Neo4j Desktop + + , or try the  + + Neo4j Aura + +  free tier. +
+ )} +
); diff --git a/src/modal/DeletePageModal.tsx b/src/modal/DeletePageModal.tsx index b6bf494fc..71a0b1cfa 100644 --- a/src/modal/DeletePageModal.tsx +++ b/src/modal/DeletePageModal.tsx @@ -1,56 +1,38 @@ import React from 'react'; -import Button from '@material-ui/core/Button'; -import TextField from '@material-ui/core/TextField'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import DeleteIcon from '@material-ui/icons/Delete'; -import PlayArrow from '@material-ui/icons/PlayArrow'; -import { Tooltip } from '@material-ui/core'; +import { Button, Dialog } from '@neo4j-ndl/react'; +import { BackspaceIconOutline, TrashIconSolid } from '@neo4j-ndl/react/icons'; /** * Configures setting the current Neo4j database connection for the dashboard. */ export const NeoDeletePageModal = ({ modalOpen, onRemove, handleClose }) => { return ( - - Delete page? - - Are you sure you want to remove this page? This cannot be undone. + + Delete page? + Are you sure you want to remove this page? This cannot be undone. + - + ); }; diff --git a/src/modal/LoadModal.tsx b/src/modal/LoadModal.tsx index 29ed057c1..5906e40f2 100644 --- a/src/modal/LoadModal.tsx +++ b/src/modal/LoadModal.tsx @@ -1,28 +1,7 @@ -import React, { useContext } from 'react'; -import Button from '@material-ui/core/Button'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import Badge from '@material-ui/core/Badge'; -import PlayArrow from '@material-ui/icons/PlayArrow'; -import { - FormControl, - InputLabel, - ListItem, - ListItemIcon, - ListItemText, - MenuItem, - Select, - TextareaAutosize, -} from '@material-ui/core'; -import CloseIcon from '@material-ui/icons/Close'; -import { withStyles } from '@material-ui/core/styles'; +import React, { useContext, useRef } from 'react'; +import { TextareaAutosize, Tooltip } from '@mui/material'; +import { withStyles } from '@mui/styles'; import { connect } from 'react-redux'; -import SystemUpdateAltIcon from '@material-ui/icons/SystemUpdateAlt'; -import PostAddIcon from '@material-ui/icons/PostAdd'; -import StorageIcon from '@material-ui/icons/Storage'; import { loadDashboardFromNeo4jByUUIDThunk, loadDashboardListFromNeo4jThunk, @@ -31,6 +10,13 @@ import { } from '../dashboard/DashboardThunks'; import { DataGrid } from '@mui/x-data-grid'; import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; +import { SideNavigationItem, Button, Dialog, Dropdown } from '@neo4j-ndl/react'; +import { + CloudArrowUpIconOutline, + PlayIconSolid, + DatabaseAddCircleIcon, + DocumentPlusIconOutline, +} from '@neo4j-ndl/react/icons'; /** * A modal to save a dashboard as a JSON text string. @@ -44,6 +30,7 @@ export const NeoLoadModal = ({ loadDatabaseListFromNeo4j, loadDashboardFromNeo4j, loadDashboardListFromNeo4j, + navItemClass, }) => { const [loadModalOpen, setLoadModalOpen] = React.useState(false); const [loadFromNeo4jModalOpen, setLoadFromNeo4jModalOpen] = React.useState(false); @@ -52,6 +39,7 @@ export const NeoLoadModal = ({ const { driver } = useContext(Neo4jContext); const [dashboardDatabase, setDashboardDatabase] = React.useState('neo4j'); const [databases, setDatabases] = React.useState(['neo4j']); + const loadFromFile = useRef(null); const handleClickOpen = () => { setLoadModalOpen(true); @@ -85,9 +73,9 @@ export const NeoLoadModal = ({ const columns = [ { field: 'id', hide: true, headerName: 'ID', width: 150 }, { field: 'date', headerName: 'Date', width: 200 }, - { field: 'title', headerName: 'Title', width: 270 }, + { field: 'title', headerName: 'Title', width: 300 }, { field: 'author', headerName: 'Author', width: 160 }, - { field: 'version', headerName: 'Version', width: 95 }, + { field: 'version', headerName: 'Version', width: 85 }, { field: 'load', headerName: 'Select', @@ -97,53 +85,36 @@ export const NeoLoadModal = ({ onClick={() => { loadDashboardFromNeo4j(driver, dashboardDatabase, c.id, handleDashboardLoadedFromNeo4j); }} - style={{ float: 'right', backgroundColor: 'white' }} - variant='contained' - size='medium' - endIcon={} + style={{ float: 'right' }} + fill='outlined' + color='neutral' + floating > Select + ); }, - width: 120, + width: 130, }, ]; return (
- - - - - - - - - - - - + + }> + Load + + + + + + Load Dashboard - - - - - - - - {/* Paste your dashboard file here to load it into NeoDash. */} -
+ + +
@@ -200,36 +168,19 @@ export const NeoLoadModal = ({ aria-label='' placeholder='Select a dashboard first, then preview it here...' /> - - {/* */} - {/* */} +
{ setLoadFromNeo4jModalOpen(false); }} aria-labelledby='form-dialog-title' > - - Select From Neo4j - { - setLoadFromNeo4jModalOpen(false); - }} - style={{ padding: '3px', float: 'right' }} - > - - - - - - - - If dashboards are saved in your current database, choose a dashboard below. - - + Select from Neo4j + If dashboards are saved in your current database, choose a dashboard below. +
- - Database - - -
+ }, + options: databases.map((database) => ({ label: database, value: database })), + value: { label: dashboardDatabase, value: dashboardDatabase }, + menuPlacement: 'auto', + }} + style={{ width: '150px', marginTop: '-65px' }} + > +
); diff --git a/src/modal/LoadSharedDashboardModal.tsx b/src/modal/LoadSharedDashboardModal.tsx index 03f0fa292..02dd05b84 100644 --- a/src/modal/LoadSharedDashboardModal.tsx +++ b/src/modal/LoadSharedDashboardModal.tsx @@ -1,21 +1,9 @@ -import React, { useContext } from 'react'; -import Button from '@material-ui/core/Button'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import Badge from '@material-ui/core/Badge'; -import PlayArrow from '@material-ui/icons/PlayArrow'; -import SaveIcon from '@material-ui/icons/Save'; -import { ListItem, ListItemIcon, ListItemText, TextareaAutosize, Tooltip } from '@material-ui/core'; -import CloseIcon from '@material-ui/icons/Close'; -import GetAppIcon from '@material-ui/icons/GetApp'; -import useMediaQuery from '@material-ui/core/useMediaQuery'; -import { useTheme, withStyles } from '@material-ui/core/styles'; +import React from 'react'; +import { withStyles } from '@mui/styles'; import { connect } from 'react-redux'; -import DashboardIcon from '@material-ui/icons/Dashboard'; +import { Button, Dialog } from '@neo4j-ndl/react'; +import { PlayIconSolid, AdjustmentsVerticalIconOutline, BackspaceIconOutline } from '@neo4j-ndl/react/icons'; + /** * A modal to save a dashboard as a JSON text string. * The button to open the modal is intended to use in a drawer at the side of the page. @@ -30,86 +18,63 @@ export const NeoLoadSharedDashboardModal = ({ shareDetails, onResetShareDetails, return (
- - - + + Loading Dashboard - - - - - - - - - {shareDetails !== undefined ? ( - <> - You are loading a Neo4j dashboard. -
- {shareDetails && shareDetails.url ? ( - <> - You will be connected to {shareDetails && shareDetails.url}. - - ) : ( - <>You will still need to specify a connection manually. - )} -

- This will override your current dashboard (if any). Continue? - - ) : ( - <> -
-
-
- - )} -
-
-
-
-
-
-
-
-
-
-
-
-
- - -
-
- + + + {shareDetails !== undefined ? ( + <> + You are loading a Neo4j dashboard. +
+ {shareDetails && shareDetails.url ? ( + <> + You will be connected to {shareDetails && shareDetails.url}. + + ) : ( + <>You will still need to specify a connection manually. + )} +

+ This will override your current dashboard (if any). Continue? + + ) : ( + <> +
+
+
+ + )} +
+ + + +
); diff --git a/src/modal/ModalUtils.tsx b/src/modal/ModalUtils.tsx new file mode 100644 index 000000000..cbb69b115 --- /dev/null +++ b/src/modal/ModalUtils.tsx @@ -0,0 +1,12 @@ +import React, { PropsWithChildren } from 'react'; +import { Typography } from '@neo4j-ndl/react'; + +export const Section = ({ children }: PropsWithChildren) => ( +
{children}
+); + +export const SectionTitle = ({ children }: PropsWithChildren) => {children}; + +export const SectionContent = ({ children }: PropsWithChildren) => ( + {children} +); diff --git a/src/modal/NotificationModal.tsx b/src/modal/NotificationModal.tsx index 63be2ca80..3bd28a64f 100644 --- a/src/modal/NotificationModal.tsx +++ b/src/modal/NotificationModal.tsx @@ -1,10 +1,4 @@ import React from 'react'; -import Button from '@material-ui/core/Button'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import PlayArrow from '@material-ui/icons/PlayArrow'; import { connect } from 'react-redux'; import { applicationHasNotification, @@ -15,9 +9,7 @@ import { getNotificationTitle, } from '../application/ApplicationSelectors'; import { clearNotification, setConnectionModalOpen } from '../application/ApplicationActions'; -import IconButton from '@material-ui/core/IconButton'; -import Badge from '@material-ui/core/Badge'; -import CloseIcon from '@material-ui/icons/Close'; +import { Dialog } from '@neo4j-ndl/react'; /** * A modal to save a dashboard as a JSON text string. @@ -35,7 +27,7 @@ export const NeoNotificationModal = ({ return (
{ if (dismissable) { @@ -46,33 +38,11 @@ export const NeoNotificationModal = ({ } }} aria-labelledby='form-dialog-title' + disableCloseButton={!dismissable} > - - {title} - { - if (dismissable) { - onNotificationClose(); - if (openConnectionModalOnClose) { - setConnectionModalOpen(); - } - } - }} - style={{ marginLeft: '40px', padding: '3px', float: 'right' }} - > - {dismissable ? ( - - - - ) : ( - <> - )} - - + {title} - - {text && text.toString()} - + {text && text.toString()}
); diff --git a/src/modal/ReportExamplesModal.tsx b/src/modal/ReportExamplesModal.tsx index f275ad0a6..82e5b4247 100644 --- a/src/modal/ReportExamplesModal.tsx +++ b/src/modal/ReportExamplesModal.tsx @@ -1,17 +1,13 @@ import React from 'react'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import CloseIcon from '@material-ui/icons/Close'; -import Badge from '@material-ui/core/Badge'; -import { Grid, ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; +import { Tooltip } from '@mui/material'; import NeoCodeEditorComponent from '../component/editor/CodeEditorComponent'; import NeoReport from '../report/Report'; -import AssessmentIcon from '@material-ui/icons/Assessment'; +import { SideNavigationItem } from '@neo4j-ndl/react'; +import { ChartBarIconSolid } from '@neo4j-ndl/react/icons'; +import { Dialog, Typography } from '@neo4j-ndl/react'; +import { Section, SectionTitle, SectionContent } from '../modal/ModalUtils'; -export const NeoReportExamplesModal = ({ database, examples, extensions }) => { +export const NeoReportExamplesModal = ({ database, examples, extensions, navItemClass }) => { const [open, setOpen] = React.useState(false); const handleClickOpen = () => { @@ -24,87 +20,66 @@ export const NeoReportExamplesModal = ({ database, examples, extensions }) => { return (
- - - - - - + + }> + Examples + + {open ? ( - - - + + + Report Examples - - - - - - -
- -
- {examples.map((example) => { + + +
+ {examples.map((example, index) => { return ( - <> -

{example.title}

- - {example.description} -
-
- - -
- -
-
+
+ {example.title} + +
+
{example.description}
+
+ +
- -
- -
-
- - -
- +
+ +
+
+
+
); })} - -
+
+
) : ( <> diff --git a/src/modal/ReportHelpModal.tsx b/src/modal/ReportHelpModal.tsx index af10c8fb9..01601cfee 100644 --- a/src/modal/ReportHelpModal.tsx +++ b/src/modal/ReportHelpModal.tsx @@ -1,52 +1,37 @@ import React from 'react'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import { Badge } from '@material-ui/core'; -import CloseIcon from '@material-ui/icons/Close'; +import { Dialog, TextLink } from '@neo4j-ndl/react'; /** * Configures setting the current Neo4j database connection for the dashboard. */ export const NeoReportHelpModal = ({ open, handleClose }) => { return ( - - - About Reports - - - - - - - - - {' '} - A report is the smallest building block of your dashboard. Each report runs a single Cypher query that loads - data from your database. By changing the report type, different visualizations can be created for the data. - See the{' '} - - Documentation - - for more on reports. -

-

- - - - - -
- Moving Reports - - - Resizing Reports - -
-
-
+ + About Reports + + {' '} + A report is the smallest building block of your dashboard. Each report runs a single Cypher query that loads + data from your database. By changing the report type, different visualizations can be created for the data. See + the{' '} + + Documentation + + for more on reports. +

+

+ + + + + +
+ Moving Reports + + + Resizing Reports + +
+
); }; diff --git a/src/modal/SaveModal.tsx b/src/modal/SaveModal.tsx index c4fd60de1..94f149632 100644 --- a/src/modal/SaveModal.tsx +++ b/src/modal/SaveModal.tsx @@ -1,36 +1,20 @@ import React, { useContext, useEffect } from 'react'; -import Button from '@material-ui/core/Button'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import Badge from '@material-ui/core/Badge'; -import SaveIcon from '@material-ui/icons/Save'; -import { - Checkbox, - FormControl, - FormControlLabel, - InputLabel, - ListItem, - ListItemIcon, - ListItemText, - MenuItem, - Select, - TextareaAutosize, - Tooltip, -} from '@material-ui/core'; -import CloseIcon from '@material-ui/icons/Close'; -import GetAppIcon from '@material-ui/icons/GetApp'; -import { withStyles } from '@material-ui/core/styles'; +import { FormControl, TextareaAutosize, Tooltip } from '@mui/material'; +import { withStyles } from '@mui/styles'; import { connect } from 'react-redux'; import { getDashboardJson } from './ModalSelectors'; import { valueIsArray, valueIsObject } from '../chart/ChartUtils'; -import StorageIcon from '@material-ui/icons/Storage'; import { applicationGetConnection } from '../application/ApplicationSelectors'; import { loadDatabaseListFromNeo4jThunk, saveDashboardToNeo4jThunk } from '../dashboard/DashboardThunks'; import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; +import { SideNavigationItem } from '@neo4j-ndl/react'; +import { + CloudArrowDownIconOutline, + DatabaseAddCircleIcon, + DocumentArrowDownIconOutline, + BackspaceIconOutline, +} from '@neo4j-ndl/react/icons'; +import { Button, Checkbox, Dialog, Dropdown } from '@neo4j-ndl/react'; /** * A modal to save a dashboard as a JSON text string. @@ -65,7 +49,13 @@ const filterNestedDict = (value: any, removedKeys: any[]) => { return value; }; -export const NeoSaveModal = ({ dashboard, connection, saveDashboardToNeo4j, loadDatabaseListFromNeo4j }) => { +export const NeoSaveModal = ({ + dashboard, + connection, + saveDashboardToNeo4j, + loadDatabaseListFromNeo4j, + navItemClass, +}) => { const [saveModalOpen, setSaveModalOpen] = React.useState(false); const [saveToNeo4jModalOpen, setSaveToNeo4jModalOpen] = React.useState(false); const [overwriteExistingDashboard, setOverwriteExistingDashboard] = React.useState(false); @@ -93,7 +83,9 @@ export const NeoSaveModal = ({ dashboard, connection, saveDashboardToNeo4j, load 'settingsOpen', 'advancedSettingsOpen', 'collapseTimeout', + 'apiKey', // Added for query-translator extension ]); + const dashboardString = JSON.stringify(filteredDashboard, null, 2); const downloadDashboard = () => { const element = document.createElement('a'); @@ -106,60 +98,35 @@ export const NeoSaveModal = ({ dashboard, connection, saveDashboardToNeo4j, load return (
- - - - - - - - - - - - + + }> + Save + + + + + + Save Dashboard - - - - - - - - - -
-
+ + +
+ + +
-
- +
{ setSaveToNeo4jModalOpen(false); }} aria-labelledby='form-dialog-title' > - - Save to Neo4j - { - setSaveToNeo4jModalOpen(false); - }} - style={{ padding: '3px', float: 'right' }} - > - - - - - - - - This will save your current dashboard as a node to your active Neo4j database. -
- Ensure you have write permissions to the database to use this feature. -
- + Save to Neo4j + + This will save your current dashboard as a node to your active Neo4j database. +
+ Ensure you have write permissions to the database to use this feature. - - - Save to Database - - - - - - - setOverwriteExistingDashboard(!overwriteExistingDashboard)} - name='overwrite' - /> - } + { + newValue && setDashboardDatabase(newValue.value); + }, + options: databases.map((database) => ({ label: database, value: database })), + value: { label: dashboardDatabase, value: dashboardDatabase }, + menuPlacement: 'auto', + }} + style={{ width: '150px', display: 'inline-block' }} + > + + + setOverwriteExistingDashboard(!overwriteExistingDashboard)} label='Overwrite' /> - +
+ + - -
- +
); diff --git a/src/modal/ShareModal.tsx b/src/modal/ShareModal.tsx index 431fb32db..afa835979 100644 --- a/src/modal/ShareModal.tsx +++ b/src/modal/ShareModal.tsx @@ -1,43 +1,26 @@ import React, { useContext } from 'react'; -import Button from '@material-ui/core/Button'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import Badge from '@material-ui/core/Badge'; -import PlayArrow from '@material-ui/icons/PlayArrow'; -import { - DialogContentText, - Divider, - FormControl, - InputLabel, - ListItem, - ListItemIcon, - ListItemText, - MenuItem, - Select, - TextareaAutosize, -} from '@material-ui/core'; -import CloseIcon from '@material-ui/icons/Close'; -import { withStyles } from '@material-ui/core/styles'; +import { Tooltip } from '@mui/material'; +import { withStyles } from '@mui/styles'; import { connect } from 'react-redux'; -import SystemUpdateAltIcon from '@material-ui/icons/SystemUpdateAlt'; -import PostAddIcon from '@material-ui/icons/PostAdd'; -import StorageIcon from '@material-ui/icons/Storage'; import { DataGrid } from '@mui/x-data-grid'; import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; -import ShareIcon from '@material-ui/icons/Share'; import NeoSetting from '../component/field/Setting'; import { loadDashboardListFromNeo4jThunk, loadDatabaseListFromNeo4jThunk } from '../dashboard/DashboardThunks'; import { applicationGetConnection } from '../application/ApplicationSelectors'; import { SELECTION_TYPES } from '../config/CardConfig'; +import { SideNavigationItem, Button, Dialog, Dropdown, TextLink } from '@neo4j-ndl/react'; +import { + ShareIconOutline, + PlayIconSolid, + DocumentCheckIconOutline, + DatabaseAddCircleIcon, +} from '@neo4j-ndl/react/icons'; -// const shareBaseURL = "http://localhost:3000"; const shareBaseURL = 'http://neodash.graphapp.io'; const shareLocalURL = window.location.origin.startsWith('file') ? shareBaseURL : window.location.origin; const styles = {}; -export const NeoShareModal = ({ connection, loadDashboardListFromNeo4j, loadDatabaseListFromNeo4j }) => { +export const NeoShareModal = ({ connection, loadDashboardListFromNeo4j, loadDatabaseListFromNeo4j, navItemClass }) => { const [shareModalOpen, setShareModalOpen] = React.useState(false); const [loadFromNeo4jModalOpen, setLoadFromNeo4jModalOpen] = React.useState(false); const [loadFromFileModalOpen, setLoadFromFileModalOpen] = React.useState(false); @@ -74,7 +57,7 @@ export const NeoShareModal = ({ connection, loadDashboardListFromNeo4j, loadData const columns = [ { field: 'id', hide: true, headerName: 'ID', width: 150 }, { field: 'date', headerName: 'Date', width: 200 }, - { field: 'title', headerName: 'Title', width: 270 }, + { field: 'title', headerName: 'Title', width: 370 }, { field: 'author', headerName: 'Author', width: 160 }, { field: 'load', @@ -88,68 +71,54 @@ export const NeoShareModal = ({ connection, loadDashboardListFromNeo4j, loadData setShareType('database'); setLoadFromNeo4jModalOpen(false); }} - style={{ float: 'right', backgroundColor: 'white' }} - variant='contained' - size='medium' - endIcon={} + style={{ float: 'right' }} + fill='outlined' + color='neutral' + floating > Select + ); }, - width: 120, + width: 130, }, ]; return (
- - - - - - - - + + }> + Share + + - - + + Share Dashboard - - - - - - - - - This window lets you create a temporary share link for your dashboard. Keep in mind that share links are not - intended as a way to publish your dashboard for users, see the  - documentation for more on - publishing. -
-
-
- Step 1: Select a dashboard to share. -
-
+ + + This window lets you create a temporary share link for your dashboard. Keep in mind that share links are not + intended as a way to publish your dashboard for users, see the  + + documentation + {' '} + for more on publishing. +
+
+
+ Step 1: Select a dashboard to share. +
+
+
-
- {shareID ? `Selected dashboard: ${shareName}` : ''} - - +
+ {shareID ? `Selected dashboard: ${shareName}` : ''} +
{shareID ? ( <> - -
- Step 2: Configure sharing settings. -
-
- { - if ((e == 'No') & (shareStandalone == 'Yes')) { - return; - } - setShareLink(null); - setShareConnectionDetails(e); - }} - /> - {shareLocalURL != shareBaseURL ? ( - { - setShareLink(null); - setShareStandalone(e); - if (e == 'Yes') { - setShareConnectionDetails('Yes'); - } - }} - /> - ) : ( - <> - )} + {' '} +
+ Step 2: Configure sharing settings. +
+
+ { + if ((e == 'No') & (shareStandalone == 'Yes')) { + return; + } + setShareLink(null); + setShareConnectionDetails(e); + }} + /> + {shareLocalURL != shareBaseURL ? ( { setShareLink(null); - setSelfHosted(e); + setShareStandalone(e); + if (e == 'Yes') { + setShareConnectionDetails('Yes'); + } }} /> - -
- + ) : ( + <> + )} + { + setShareLink(null); + setSelfHosted(e); + }} + /> + +
) : ( <> )} {shareLink ? ( - + <>
Step 3: Use the generated link to view the dashboard:
- + {shareLink} - +
-
+ ) : ( <> )} -
+
{ setLoadFromNeo4jModalOpen(false); }} aria-labelledby='form-dialog-title' > - - Select From Neo4j - { - setLoadFromNeo4jModalOpen(false); - }} - style={{ padding: '3px', float: 'right' }} - > - - - - - - - Choose a dashboard to share below. - + Select From Neo4j + + Choose a dashboard to share below.
- - Database - - -
+ }, + options: databases.map((database) => ({ label: database, value: database })), + value: { label: dashboardDatabase, value: dashboardDatabase }, + menuPlacement: 'auto', + }} + style={{ width: '150px' }} + > +
{ setLoadFromFileModalOpen(false); }} aria-labelledby='form-dialog-title' > - - Select from URL - { - setLoadFromFileModalOpen(false); + Select from URL + + To share a dashboard file directly, make it accessible{' '} + + online + + . Then, paste the direct link here: + { + setShareFileURL(e); }} - style={{ padding: '3px', float: 'right' }} - > - - - - - - - - To share a dashboard file directly, make it accessible  - - online - - . Then, paste the direct link here: - { - setShareFileURL(e); - }} - /> + /> +
- - +
+
); diff --git a/src/modal/UpgradeOldDashboardModal.tsx b/src/modal/UpgradeOldDashboardModal.tsx index e0c093918..ba0692144 100644 --- a/src/modal/UpgradeOldDashboardModal.tsx +++ b/src/modal/UpgradeOldDashboardModal.tsx @@ -1,48 +1,46 @@ import React from 'react'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import Button from '@material-ui/core/Button'; -import DeleteIcon from '@material-ui/icons/Delete'; -import { TextareaAutosize } from '@material-ui/core'; +import { TextareaAutosize } from '@mui/material'; +import { Button, Dialog } from '@neo4j-ndl/react'; +import { TrashIconOutline, PlayIconSolid } from '@neo4j-ndl/react/icons'; export const NeoUpgradeOldDashboardModal = ({ open, text, clearOldDashboard, loadDashboard }) => { return (
- - Old Dashboard Found - + + Old Dashboard Found + We've found a dashboard built with an old version of NeoDash. Would you like to attempt an upgrade, or start from scratch?
Make sure you back up this dashboard first! -
- - +
+ + +
-
+
); diff --git a/src/modal/WelcomeScreenModal.tsx b/src/modal/WelcomeScreenModal.tsx index 34fe2774b..a835bf636 100644 --- a/src/modal/WelcomeScreenModal.tsx +++ b/src/modal/WelcomeScreenModal.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import Button from '@material-ui/core/Button'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import { Tooltip } from '@material-ui/core'; +import { Tooltip } from '@mui/material'; +import { Button, Dialog, TextLink } from '@neo4j-ndl/react'; +import { + BoltIconSolid, + ExclamationTriangleIconSolid, + BackspaceIconOutline, + PlayIconSolid, +} from '@neo4j-ndl/react/icons'; /** * Configures setting the current Neo4j database connection for the dashboard. @@ -37,15 +37,13 @@ export const NeoWelcomeScreenModal = ({ return (
- - + + NeoDash - Neo4j Dashboard Builder - - ⚡ - - - - + + + + - + {hasCachedDashboard ? ( )} - - - - + + - + - -
- -
- - - - NeoDash is a tool for building standalone Neo4j dashboards. Need advice on building an integrated - solution?{' '} - - Get in touch - - ! - - - + + +
+ NeoDash is a tool for building standalone Neo4j dashboards. Need advice on building an integrated solution?{' '} + + Get in touch + + ! +
+
{/* Prompt when creating new dashboard with existing cache */} - - - Create new dashboard - - ⚠️ - - - + + + Create New Dashboard + {/* */} + + Are you sure you want to create a new dashboard? This will remove your currently cached dashboard. - - - - - - - - - + + + + +
); diff --git a/src/page/Page.tsx b/src/page/Page.tsx index 7d2fac4ad..b9f7923ba 100644 --- a/src/page/Page.tsx +++ b/src/page/Page.tsx @@ -4,7 +4,7 @@ import NeoAddCard from '../card/CardAddButton'; import NeoCard from '../card/Card'; import { getReports } from './PageSelectors'; import { addReportThunk, removeReportThunk, updatePageLayoutThunk, cloneReportThunk } from './PageThunks'; -import Grid from '@material-ui/core/Grid'; +import Grid from '@mui/material/Grid'; import { getDashboardIsEditable, getPageNumber } from '../settings/SettingsSelectors'; import { getDashboardSettings } from '../dashboard/DashboardSelectors'; import { Responsive, WidthProvider } from 'react-grid-layout'; @@ -26,25 +26,27 @@ export const NeoPage = ({ isLoaded = true, // Whether the page is loaded and the cards can be displayed. onPageLayoutUpdate = () => {}, // action to take when the page layout is updated. }) => { - const getReportIndex = (pagenumber: number, index: number) => { - return `${pagenumber}:${index}`; + const getReportKey = (pagenumber: number, id: string) => { + return `${pagenumber}:${id}`; }; - const defaultLayouts = [ - { - x: 0, - y: 0, - i: getReportIndex(pagenumber, 999999), - w: 3, - h: 2, - isDraggable: false, - }, - ]; + const defaultLayouts = { + lg: [ + { + x: 0, + y: 0, + i: getReportKey(pagenumber, '999999'), + w: 3, + h: 2, + isDraggable: false, + }, + ], + }; const loadingMessage =
Loading card...
; const [isDragging, setIsDragging] = React.useState(false); const [layouts, setLayouts] = React.useState(defaultLayouts); - const [lastElement, setLastElement] = React.useState(
); + const [lastElement, setLastElement] = React.useState(
); const [animated, setAnimated] = React.useState(false); // To turn off animations when cards are dragged around. const availableHandles = () => { @@ -101,22 +103,23 @@ export const NeoPage = ({ setLayouts({ // @ts-ignore lg: [ - ...reports.map((report, index) => { + ...reports.map((report) => { return { - x: report.x !== undefined ? report.x : 0, - y: report.y !== undefined ? report.y : 0, - i: getReportIndex(pagenumber, index), - w: report.width !== undefined ? Math.max(parseInt(report.width), 2) : 3, - h: report.height !== undefined ? Math.max(parseInt(report.height), 1) : 2, + x: report.x || 0, + y: report.y || 0, + i: getReportKey(pagenumber, report.id), + w: Math.max(parseInt(report.width), 2) || 3, + h: Math.max(parseInt(report.height), 1) || 2, minW: 2, minH: 1, resizeHandles: availableHandles(), + isDraggable: true, }; }), { x: x, y: y, - i: getReportIndex(pagenumber, 999999), + i: getReportKey(pagenumber, '999999'), w: 3, h: 2, minW: 3, @@ -127,7 +130,7 @@ export const NeoPage = ({ ], }); setLastElement( - + { const { x, y } = getAddCardButtonPosition(); @@ -177,13 +180,13 @@ export const NeoPage = ({ onPageLayoutUpdate(newLayout); }} > - {reports.map((report, index) => { + {reports.map((report) => { const w = 12; + const { id } = report; // @ts-ignore return ( { + onClonePressed={(id) => { const { x, y } = getAddCardButtonPosition(); - onClonePressed(index, x, y); + onClonePressed(id, x, y); }} /> ); })} - {editable && !isDragging ? lastElement :
} + {editable && !isDragging ? lastElement :
}
); @@ -221,8 +224,8 @@ const mapStateToProps = (state) => ({ }); const mapDispatchToProps = (dispatch) => ({ - onRemovePressed: (index) => dispatch(removeReportThunk(index)), - onClonePressed: (index, x, y) => dispatch(cloneReportThunk(index, x, y)), + onRemovePressed: (id) => dispatch(removeReportThunk(id)), + onClonePressed: (id, x, y) => dispatch(cloneReportThunk(id, x, y)), onCreatePressed: (x, y, width, height) => dispatch(addReportThunk(x, y, width, height, undefined)), onPageLayoutUpdate: (layout) => dispatch(updatePageLayoutThunk(layout)), }); diff --git a/src/page/PageActions.ts b/src/page/PageActions.ts index 0c0511385..1ecb05596 100644 --- a/src/page/PageActions.ts +++ b/src/page/PageActions.ts @@ -5,9 +5,9 @@ export const createReport = (pagenumber: number, report: any) => ({ }); export const REMOVE_REPORT = 'PAGE/REMOVE_REPORT'; -export const removeReport = (pagenumber: number, index: any) => ({ +export const removeReport = (pagenumber: number, id: any) => ({ type: REMOVE_REPORT, - payload: { pagenumber, index }, + payload: { pagenumber, id }, }); export const UPDATE_ALL_CARD_POSITIONS_IN_PAGE = 'PAGE/UPDATE_ALL_CARD_POSITIONS_IN_PAGE'; diff --git a/src/page/PageReducer.ts b/src/page/PageReducer.ts index f2d65f56a..70aecfc11 100644 --- a/src/page/PageReducer.ts +++ b/src/page/PageReducer.ts @@ -6,6 +6,7 @@ import { FORCE_REFRESH_PAGE, UPDATE_ALL_CARD_POSITIONS_IN_PAGE, } from './PageActions'; +import { createUUID } from '../dashboard/DashboardThunks'; const update = (state, mutations) => Object.assign({}, state, mutations); @@ -14,6 +15,7 @@ export const FIRST_PAGE_INITIAL_STATE = { title: 'Main Page', reports: [ { + id: createUUID(), title: 'Hi there 👋', query: '**This is your first dashboard!** \n \nYou can click (⋮) to edit this report, or add a new report to get started. You can run any Cypher query directly from each report and render data in a variety of formats. \n \nTip: try _renaming_ this report by editing the title text. You can also edit the dashboard header at the top of the screen.\n\n\n', @@ -26,6 +28,7 @@ export const FIRST_PAGE_INITIAL_STATE = { settings: {}, }, { + id: createUUID(), title: '', query: 'MATCH (n)-[e]->(m) RETURN n,e,m LIMIT 20\n\n\n', width: 3, @@ -57,7 +60,8 @@ export const pageReducer = (state = PAGE_INITIAL_STATE, action: { type: any; pay } // Updates a report at a given page and index. if (action.type.startsWith('PAGE/CARD/')) { - const { index } = payload; + const { id } = payload; + const index = state.reports.findIndex((o) => o.id === id); return { ...state, reports: [ @@ -80,19 +84,12 @@ export const pageReducer = (state = PAGE_INITIAL_STATE, action: { type: any; pay } case REMOVE_REPORT: { // Removes the card at a given index on a selected page number. - const { index } = payload; - const cardsInFront = state.reports.slice(0, index); - const cardsBehind = state.reports.slice(index + 1); - - // if there's card after the removed card, it will take it's place. - // We make sure that the transition is disabled in this case. - if (cardsBehind.length > 0) { - // @ts-ignore - cardsBehind[0].collapseTimeout = 0; - } + const { id } = payload; + let cards = state.reports.filter((o) => o.id !== id); + // cards.forEach(c => c.collapseTimeout = 0 ); return { ...state, - reports: cardsInFront.concat(cardsBehind), + reports: cards, }; } case UPDATE_ALL_CARD_POSITIONS_IN_PAGE: { diff --git a/src/page/PageThunks.ts b/src/page/PageThunks.ts index 9b218c34c..0077d127b 100644 --- a/src/page/PageThunks.ts +++ b/src/page/PageThunks.ts @@ -1,6 +1,7 @@ import { createNotification } from '../application/ApplicationActions'; import { CARD_INITIAL_STATE } from '../card/CardReducer'; import { createReport, removeReport, updateAllCardPositionsInPage } from './PageActions'; +import { createUUID } from '../dashboard/DashboardThunks'; export const createNotificationThunk = (title: any, message: any) => (dispatch: any) => { dispatch(createNotification(title, message)); @@ -10,7 +11,7 @@ export const addReportThunk = (x: number, y: number, width: number, height: number, data: any) => (dispatch: any, getState: any) => { try { const initialState = data !== undefined ? data : CARD_INITIAL_STATE; - const report = { ...initialState, x: x, y: y, width: width, height: height }; + const report = { ...initialState, x: x, y: y, width: width, height: height, id: createUUID() }; const state = getState(); const { pagenumber } = state.dashboard.settings; dispatch(createReport(pagenumber, report)); @@ -19,21 +20,21 @@ export const addReportThunk = } }; -export const removeReportThunk = (index: number) => (dispatch: any, getState: any) => { +export const removeReportThunk = (id: string) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - dispatch(removeReport(pagenumber, index)); + dispatch(removeReport(pagenumber, id)); } catch (e) { dispatch(createNotificationThunk('Cannot remove report', e)); } }; -export const cloneReportThunk = (index: number, x: number, y: number) => (dispatch: any, getState: any) => { +export const cloneReportThunk = (id: string, x: number, y: number) => (dispatch: any, getState: any) => { try { const state = getState(); const { pagenumber } = state.dashboard.settings; - const data = { ...state.dashboard.pages[pagenumber].reports[index] }; + const data = { ...state.dashboard.pages[pagenumber].reports.find((o) => o.id === id) }; data.settingsOpen = false; dispatch(addReportThunk(x, y, data.width, data.height, data)); } catch (e) { diff --git a/src/report/Report.tsx b/src/report/Report.tsx index 21e9940bf..4740bc84b 100644 --- a/src/report/Report.tsx +++ b/src/report/Report.tsx @@ -1,24 +1,30 @@ -import { Chip, Tooltip } from '@material-ui/core'; +import { Chip, Tooltip } from '@mui/material'; import React, { useState, useEffect } from 'react'; -import WarningIcon from '@material-ui/icons/Warning'; import { QueryStatus, runCypherQuery } from './ReportQueryRunner'; import debounce from 'lodash/debounce'; import { useCallback } from 'react'; -import { Typography } from '@material-ui/core'; -import CircularProgress from '@material-ui/core/CircularProgress'; import NeoCodeViewerComponent, { NoDrawableDataErrorMessage } from '../component/editor/CodeViewerComponent'; import { DEFAULT_ROW_LIMIT, HARD_ROW_LIMITING, RUN_QUERY_DELAY_MS } from '../config/ReportConfig'; -import { MoreVert } from '@material-ui/icons'; +import { MoreVert } from '@mui/icons-material'; import { Neo4jContext, Neo4jContextState } from 'use-neo4j/dist/neo4j.context'; import { useContext } from 'react'; import NeoTableChart from '../chart/table/TableChart'; import { getReportTypes } from '../extensions/ExtensionUtils'; import { SELECTION_TYPES } from '../config/CardConfig'; +import { LoadingSpinner } from '@neo4j-ndl/react'; +import { ExclamationTriangleIconSolid } from '@neo4j-ndl/react/icons'; import { connect } from 'react-redux'; -import { updateDashboardSetting } from '../settings/SettingsActions'; import { setPageNumberThunk } from '../settings/SettingsThunks'; +import { EXTENSIONS } from '../extensions/ExtensionConfig'; +import { getPageNumber } from '../settings/SettingsSelectors'; +import { getPrepopulateReportExtension } from '../extensions/state/ExtensionSelectors'; +import { deleteSessionStoragePrepopulationReportFunction } from '../extensions/state/ExtensionActions'; + +const DEFAULT_LOADING_ICON = ; export const NeoReport = ({ + pagenumber = '', // page number that the report is on. + id = '', // ID of the report / card. database = 'neo4j', // The Neo4j database to run queries onto. query = '', // The Cypher query used to populate the report. lastRunTimestamp = 0, // Timestamp of the last query run for this report. @@ -43,12 +49,16 @@ export const NeoReport = ({ type = 'table', // The type of report as a string. expanded = false, // whether the report is visualized in a fullscreen view. extensions = {}, // A set of enabled extensions. + getCustomDispatcher = () => {}, ChartType = NeoTableChart, // The report component to render with the query results. + prepopulateExtensionName, + deletePrepopulationReportFunction, }) => { const [records, setRecords] = useState(null); const [timer, setTimer] = useState(null); const [status, setStatus] = useState(QueryStatus.NO_QUERY); const { driver } = useContext(Neo4jContext); + const [loadingIcon, setLoadingIcon] = React.useState(DEFAULT_LOADING_ICON); if (!driver) { throw new Error( '`driver` not defined. Have you added it into your app as ?' @@ -91,39 +101,66 @@ export const NeoReport = ({ const useNodePropsAsFields = reportTypes[type].useNodePropsAsFields == true; const useReturnValuesAsFields = reportTypes[type].useReturnValuesAsFields == true; - if (debounced) { - setStatus(QueryStatus.RUNNING); - debouncedRunCypherQuery( + // Logic to run a query + const executeQuery = (newQuery) => { + setLoadingIcon(DEFAULT_LOADING_ICON); + if (debounced) { + debouncedRunCypherQuery( + driver, + database, + newQuery, + parameters, + rowLimit, + setStatus, + setRecords, + setFields, + fields, + useNodePropsAsFields, + useReturnValuesAsFields, + HARD_ROW_LIMITING, + queryTimeLimit + ); + } else { + runCypherQuery( + driver, + database, + newQuery, + parameters, + rowLimit, + setStatus, + setRecords, + setFields, + fields, + useNodePropsAsFields, + useReturnValuesAsFields, + HARD_ROW_LIMITING, + queryTimeLimit + ); + } + }; + + setStatus(QueryStatus.RUNNING); + + // If a custom prepopulating function is present in the session storage... + // ... Await for the prepopulating function to complete before running the (normal) query logic. + // Else just run the normal query. + // Finally, remove the prepopulating function from session storage. + if (prepopulateExtensionName) { + setLoadingIcon(EXTENSIONS[prepopulateExtensionName].customLoadingIcon); + EXTENSIONS[prepopulateExtensionName].prepopulateReportFunction( driver, - database, - query, - parameters, - rowLimit, - setStatus, - setRecords, - setFields, - fields, - useNodePropsAsFields, - useReturnValuesAsFields, - HARD_ROW_LIMITING, - queryTimeLimit + getCustomDispatcher(), + pagenumber, + id, + type, + extensions, + (result) => { + executeQuery(result); + } ); + deletePrepopulationReportFunction(id); } else { - runCypherQuery( - driver, - database, - query, - parameters, - rowLimit, - setStatus, - setRecords, - setFields, - fields, - useNodePropsAsFields, - useReturnValuesAsFields, - HARD_ROW_LIMITING, - queryTimeLimit - ); + executeQuery(query); } }; @@ -189,21 +226,7 @@ export const NeoReport = ({
); } else if (status == QueryStatus.RUNNING) { - return ( - - - - ); + return loadingIcon; } else if (status == QueryStatus.NO_DATA) { return ; } else if (status == QueryStatus.NO_DRAWABLE_DATA) { @@ -245,9 +268,12 @@ export const NeoReport = ({ title={`Over ${rowLimit} row(s) were returned, results have been truncated.`} placement='left' aria-label='host' + disableInteractive > -
@@ -289,12 +315,21 @@ export const NeoReport = ({ ); }; -const mapStateToProps = () => ({}); +const mapStateToProps = (state, ownProps) => ({ + pagenumber: getPageNumber(state), + prepopulateExtensionName: getPrepopulateReportExtension(state, ownProps.id), +}); const mapDispatchToProps = (dispatch) => ({ setPageNumber: (index: number) => { dispatch(setPageNumberThunk(index)); }, + deletePrepopulationReportFunction: (id) => { + dispatch(deleteSessionStoragePrepopulationReportFunction(id)); + }, + getCustomDispatcher: () => { + return dispatch; + }, }); export default connect(mapStateToProps, mapDispatchToProps)(NeoReport); diff --git a/src/report/ReportQueryRunner.ts b/src/report/ReportQueryRunner.ts index 8f897a94f..483b1a6ad 100644 --- a/src/report/ReportQueryRunner.ts +++ b/src/report/ReportQueryRunner.ts @@ -5,6 +5,7 @@ export enum QueryStatus { NO_QUERY, // No query specified NO_DATA, // No data was returned, therefore we can't draw it. NO_DRAWABLE_DATA, // There is data returned, but we can't draw it + WAITING, // The report is waiting for custom logic to be executed. RUNNING, // The report query is running. TIMED_OUT, // Query has reached the time limit. COMPLETE, // There is data returned, and we can visualize it all. @@ -12,6 +13,7 @@ export enum QueryStatus { ERROR, // Something broke, likely the cypher query is invalid. } +// TODO: create a readOnly version of this method or inject a property /** * Runs a Cypher query using the specified driver. * @param driver - an instance of a Neo4j driver. @@ -25,7 +27,7 @@ export enum QueryStatus { * @param queryTimeLimit - maximum query time in seconds. * @returns */ -export function runCypherQuery( +export async function runCypherQuery( driver, database = '', query = '', @@ -70,7 +72,7 @@ export function runCypherQuery( } } - transaction + await transaction .run(query, parameters) .then((res) => { // @ts-ignore @@ -102,8 +104,8 @@ export function runCypherQuery( transaction.commit(); return; } else if (records.length > rowLimit) { - setRecords(records.slice(0, rowLimit)); setStatus(QueryStatus.COMPLETE_TRUNCATED); + setRecords(records.slice(0, rowLimit)); // console.log("TODO remove this - QUERY RETURNED WAS TRUNCTURED!") transaction.commit(); return; diff --git a/src/report/ReportRecordProcessing.tsx b/src/report/ReportRecordProcessing.tsx index aa8ac840b..6236209ff 100644 --- a/src/report/ReportRecordProcessing.tsx +++ b/src/report/ReportRecordProcessing.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { Chip } from '@material-ui/core'; -import { withStyles } from '@material-ui/core/styles'; -import Tooltip from '@material-ui/core/Tooltip'; +import { Chip, Tooltip } from '@mui/material'; +import { GraphLabel, TextLink } from '@neo4j-ndl/react'; +import { withStyles } from '@mui/styles'; import { getRecordType, toNumber, @@ -133,7 +133,11 @@ export function RenderNode(value, hoverable = true) { } export function RenderNodeChip(text, color = 'lightgrey', border = '0px') { - return ; + return ( + + {text} + + ); } export function RenderRelationshipChip(text, direction = undefined, color = 'lightgrey') { @@ -147,7 +151,7 @@ export function RenderRelationshipChip(text, direction = undefined, color = 'lig paddingLeft: 5, clipPath: direction == undefined ? 'none' : direction ? rightRelationship : leftRelationship, }} - label={`${text} `} + label={text} /> ); } @@ -213,9 +217,9 @@ function RenderString(value) { const str = value ? value.toString() : ''; if (str.startsWith('http') || str.startsWith('https')) { return ( - + {str} - + ); } return str; diff --git a/src/report/ReportWrapper.tsx b/src/report/ReportWrapper.tsx index 40d9c7be3..3b0b2c957 100644 --- a/src/report/ReportWrapper.tsx +++ b/src/report/ReportWrapper.tsx @@ -2,8 +2,6 @@ import React, { useEffect } from 'react'; import NeoReport from './Report'; import { withErrorBoundary, useErrorBoundary } from 'react-use-error-boundary'; import NeoCodeViewerComponent from '../component/editor/CodeViewerComponent'; -import { updateReportSetting } from '../card/CardActions'; -import { createNotification } from '../application/ApplicationActions'; /** * Error boundary wrapping the report object, to ensure that unexpected errors are handled at the report level. @@ -28,6 +26,7 @@ const ErrorBoundary = withErrorBoundary(({ children, resetTrigger }) => { }); export const NeoReportWrapper = ({ + id, database, query, lastRunTimestamp, @@ -52,6 +51,7 @@ export const NeoReportWrapper = ({ return ( ({ + type: RESET_STATE, + payload: {}, +}); + +export const STORE_VALUE_SESSION_STORAGE = `${SESSION_STORAGE_PREFIX}/STORE_VALUE`; +/** + * Sets a value with the key passed in input + * @param key Key to use to access the SessionStorage + * @param value Value to add inside the SessionStorage + */ +export const setSessionStorageValue = (key, value) => ({ + type: STORE_VALUE_SESSION_STORAGE, + payload: { key, value }, +}); + +/** + * Deletes a key from the SessionStorage + * @param key Key to use to access the SessionStorage + */ +export const DELETE_VALUE_SESSION_STORAGE = `${SESSION_STORAGE_PREFIX}/DELETE_VALUE`; +export const deleteSessionStorageValue = (key) => ({ + type: DELETE_VALUE_SESSION_STORAGE, + payload: { key }, +}); + +/** + * Deletes all the keys that start with the prefix passed in input + * @param prefix Prefix used to match the keys inside the SessionStorage + */ +export const DELETE_ALL_KEYS_WITH_PREFIX_SESSION_STORAGE = `${SESSION_STORAGE_PREFIX}/DELETE_ALL_KEYS_WITH_PREFIX`; +export const deleteAllKeysInSessionStorageWithPrefix = (prefix) => ({ + type: DELETE_ALL_KEYS_WITH_PREFIX_SESSION_STORAGE, + payload: { prefix }, +}); diff --git a/src/sessionStorage/SessionStorageReducer.ts b/src/sessionStorage/SessionStorageReducer.ts new file mode 100644 index 000000000..b54b82ec3 --- /dev/null +++ b/src/sessionStorage/SessionStorageReducer.ts @@ -0,0 +1,51 @@ +/** + * Reducers define changes to the application state when a given action + */ + +import { + DELETE_ALL_KEYS_WITH_PREFIX_SESSION_STORAGE, + DELETE_VALUE_SESSION_STORAGE, + RESET_STATE, + STORE_VALUE_SESSION_STORAGE, +} from './SessionStorageActions'; + +export const initialState = {}; + +const update = (state, mutations) => Object.assign({}, state, mutations); + +export const sessionStorageReducer = (state = initialState, action: { type: any; payload: any }) => { + const { type, payload } = action; + + switch (type) { + case RESET_STATE: { + return {}; + } + case STORE_VALUE_SESSION_STORAGE: { + const { key, value } = payload; + let newValue = {}; + newValue[key] = value; + return update(state, newValue); + } + + case DELETE_VALUE_SESSION_STORAGE: { + const { key } = payload; + let newState = { ...state }; + delete newState[key]; + return newState; + } + case DELETE_ALL_KEYS_WITH_PREFIX_SESSION_STORAGE: { + const { prefix } = payload; + let newState = { ...state }; + // Deleting all the values that elements that present that + Object.keys(newState).map((key) => { + if (key.startsWith(prefix)) { + delete newState[key]; + } + }); + return newState; + } + default: { + return state; + } + } +}; diff --git a/src/sessionStorage/SessionStorageSelectors.ts b/src/sessionStorage/SessionStorageSelectors.ts new file mode 100644 index 000000000..951a4d76b --- /dev/null +++ b/src/sessionStorage/SessionStorageSelectors.ts @@ -0,0 +1,6 @@ +const getSessionStorage = (state: any) => state.sessionStorage; + +export const getSessionStorageValue = (state: any, key: any) => { + const sessionStorage = getSessionStorage(state); + return sessionStorage[key] ? sessionStorage[key] : undefined; +}; diff --git a/src/settings/SettingsModal.tsx b/src/settings/SettingsModal.tsx index c3b9c355b..377aab891 100644 --- a/src/settings/SettingsModal.tsx +++ b/src/settings/SettingsModal.tsx @@ -1,17 +1,12 @@ import React from 'react'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import IconButton from '@material-ui/core/IconButton'; -import CloseIcon from '@material-ui/icons/Close'; -import SettingsIcon from '@material-ui/icons/Settings'; -import Badge from '@material-ui/core/Badge'; -import { ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; +import { Tooltip } from '@mui/material'; import NeoSetting from '../component/field/Setting'; import { DASHBOARD_SETTINGS } from '../config/DashboardConfig'; +import { SideNavigationItem } from '@neo4j-ndl/react'; +import { Cog6ToothIconOutline } from '@neo4j-ndl/react/icons'; +import { Dialog } from '@neo4j-ndl/react'; -export const NeoSettingsModal = ({ dashboardSettings, updateDashboardSetting }) => { +export const NeoSettingsModal = ({ dashboardSettings, updateDashboardSetting, navItemClass }) => { const [open, setOpen] = React.useState(false); const handleClickOpen = () => { @@ -23,17 +18,15 @@ export const NeoSettingsModal = ({ dashboardSettings, updateDashboardSetting }) }; const settings = DASHBOARD_SETTINGS; - // Else, build the advanced settings view. const advancedDashboardSettings = (
{Object.keys(settings) .filter((setting) => !settings[setting].hidden) .map((setting) => ( - <> +
updateDashboardSetting(setting, e)} />
- +
))}
); return (
- - - - - - + + }> + Settings + + - - - + + + Dashboard Settings - - - - - - - - - You can modify settings for your entire dashboard here. -
-
- {advancedDashboardSettings} -
-
+ + + You can modify settings for your entire dashboard here. +
+
+ {advancedDashboardSettings} +
+
); diff --git a/src/settings/SettingsReducer.ts b/src/settings/SettingsReducer.ts index d1355f401..b881a7436 100644 --- a/src/settings/SettingsReducer.ts +++ b/src/settings/SettingsReducer.ts @@ -18,7 +18,7 @@ export const settingsReducer = (state = SETTINGS_INITIAL_STATE, action: { type: const { type, payload } = action; if (!action.type.startsWith('SETTINGS/')) { - return state.settings; + return state; } // Else, deal with page-level operations. diff --git a/src/settings/SettingsSelectors.ts b/src/settings/SettingsSelectors.ts index c4545b20b..a35c2ebda 100644 --- a/src/settings/SettingsSelectors.ts +++ b/src/settings/SettingsSelectors.ts @@ -12,19 +12,19 @@ The database related to a card is, at its start, the same as the one defined ins a user can modify the database that is used by a card with a new option inside the card itself. TODO: too overloaded, define two different functions based on the scope (global db or card specific db) */ -export const getDatabase = (state: any, pageNumber: number, cardIndex: number) => { - if (state == undefined || pageNumber == undefined || cardIndex == undefined) { +export const getDatabase = (state: any, pagenumber: number, id: number) => { + if (state == undefined || pagenumber == undefined || id == undefined) { // TODO - use DMBS default database instead of neo4j. return 'neo4j'; } if ( - state.dashboard.pages[pageNumber] == undefined || - state.dashboard.pages[pageNumber].reports[cardIndex] == undefined + state.dashboard.pages[pagenumber] == undefined || + state.dashboard.pages[pagenumber].reports.find((o) => o.id === id) == undefined ) { // TODO - use DMBS default database instead of neo4j. return 'neo4j'; } - const reportDatabase = state.dashboard.pages[pageNumber].reports[cardIndex].database; + const reportDatabase = state.dashboard.pages[pagenumber].reports.find((o) => o.id === id).database; if (reportDatabase !== undefined) { return reportDatabase; } diff --git a/src/settings/SettingsThunks.ts b/src/settings/SettingsThunks.ts index 0522e2350..267911ae5 100644 --- a/src/settings/SettingsThunks.ts +++ b/src/settings/SettingsThunks.ts @@ -16,8 +16,8 @@ export const setPageNumberThunk = (number) => (dispatch: any, getState: any) => // Make sure that we don't have weird transitions with the settings popups. const page = pages[number]; - page.reports.map((report, i) => { - dispatch(hardResetCardSettings(number, i)); + page.reports.map((report) => { + dispatch(hardResetCardSettings(number, report.id)); }); } catch (e) { dispatch(createNotificationThunk('Unable to set page number', e)); @@ -92,7 +92,7 @@ export const updateParametersToNeo4jTypeThunk = () => (dispatch: any, getState: Object.keys(parameters).forEach((key) => { if (isCastableToNeo4jDate(parameters[key])) { parameters[key] = castToNeo4jDate(parameters[key]); - } else if (parameters[key] === undefined) { + } else if (parameters[key] == undefined) { delete parameters[key]; } }); diff --git a/src/store.ts b/src/store.ts index 4aeb976e4..5ae34a0e2 100644 --- a/src/store.ts +++ b/src/store.ts @@ -6,6 +6,7 @@ import thunk from 'redux-thunk'; import { composeWithDevTools } from '@redux-devtools/extension'; import { dashboardReducer } from './dashboard/DashboardReducer'; import { applicationReducer } from './application/ApplicationReducer'; +import { sessionStorageReducer } from './sessionStorage/SessionStorageReducer'; /** * Set up the store (browser cache), as well as the reducers that can update application state. @@ -19,6 +20,7 @@ const persistConfig = { const reducers = { dashboard: dashboardReducer, application: applicationReducer, + sessionStorage: sessionStorageReducer, }; const rootReducer = combineReducers(reducers); diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 000000000..5eac08d13 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,7 @@ +module.exports = { + content: ['./src/**/*.{js,jsx,ts,tsx}'], + presets: [require('@neo4j-ndl/base').tailwindConfig], + corePlugins: { + preflight: false, + }, +}; diff --git a/tsconfig.json b/tsconfig.json index dcd1dc5cc..76cd5cc88 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "target": "ES2022", + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -21,7 +17,5 @@ "noImplicitAny": false, "noFallthroughCasesInSwitch": true }, - "include": [ - "src" - ] + "include": ["src"] } diff --git a/webpack.config.js b/webpack.config.js index b2ac6dfe5..dba21a3d0 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,17 +1,22 @@ -const path = require('path'); -const webpack = require('webpack'); - +const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); const rules = [ { test: /\.(js|jsx|ts|tsx)$/, exclude: /(node_modules)/, loader: 'babel-loader', - options: { presets: ['@babel/env'] }, + options: { + presets: ['@babel/env'], + //plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean), + }, }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, + { + test: /\.pcss$/, + use: ['style-loader', 'css-loader', 'postcss-loader'], + }, { test: /\.js$/, exclude: /(node_modules\/react-leaflet-heatmap-layer-v3)/, @@ -29,7 +34,10 @@ const rules = [ module.exports = (env) => { const production = env.production; return { - entry: './src/index.tsx', + experiments: { + topLevelAwait: true, + }, + entry: ['./src/index.tsx'], mode: production ? 'production' : 'development', devtool: production ? undefined : 'source-map', module: { @@ -43,7 +51,7 @@ module.exports = (env) => { port: 3000, hot: true, }, - plugins: production ? [] : [new webpack.HotModuleReplacementPlugin()], + plugins: production ? [] : [new ReactRefreshWebpackPlugin()], ignoreWarnings: [/Failed to parse source map/], }; }; diff --git a/yarn.lock b/yarn.lock index 4862bf8c8..e158d8c0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.1.0.tgz#417fef4a143f4396ad0b3b4351fee21323f15aa8" integrity sha512-mMVJ/j/GbZ/De4ZHWbQAQO1J6iVnjtZLc9WEdkUQb8S/Bu2cAF2bETXUgMAdvMG3/ngtKmcNBe+Zms9bg6jnQQ== +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + "@ampproject/remapping@^2.1.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -15,6 +20,14 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@babel/cli@^7.16.8": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.20.7.tgz#8fc12e85c744a1a617680eacb488fab1fcd35b7c" @@ -38,11 +51,44 @@ dependencies: "@babel/highlight" "^7.18.6" +"@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5": version "7.20.14" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.14.tgz#4106fc8b755f3e3ee0a0a7c27dde5de1d2b2baf8" integrity sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw== +"@babel/compat-data@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.6.tgz#15606a20341de59ba02cd2fcc5086fcbe73bf544" + integrity sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg== + +"@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.6.tgz#aafafbe86e9a1679d876b99dc46382964ef72494" + integrity sha512-HPIyDa6n+HKw5dEuway3vVAhBboYCtREBMp+IWeseZy6TFtzn6MHkCH2KKYUOC/vKKwgSMHQW4htBOrmuRPXfw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helpers" "^7.22.6" + "@babel/parser" "^7.22.6" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" + "@nicolo-ribaudo/semver-v6" "^6.3.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + "@babel/core@^7.16.12": version "7.20.12" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.12.tgz#7930db57443c6714ad216953d1356dac0eb8496d" @@ -73,6 +119,16 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.5.tgz#1e7bf768688acfb05cf30b2369ef855e82d984f7" + integrity sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA== + dependencies: + "@babel/types" "^7.22.5" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.16.0", "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -99,6 +155,17 @@ lru-cache "^5.1.1" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz#e30d61abe9480aa5a83232eb31c111be922d2e52" + integrity sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-validator-option" "^7.22.5" + "@nicolo-ribaudo/semver-v6" "^6.3.3" + browserslist "^4.21.9" + lru-cache "^5.1.1" + "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.12", "@babel/helper-create-class-features-plugin@^7.20.5", "@babel/helper-create-class-features-plugin@^7.20.7": version "7.20.12" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz#4349b928e79be05ed2d1643b20b99bb87c503819" @@ -138,6 +205,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + "@babel/helper-explode-assignable-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" @@ -153,6 +225,14 @@ "@babel/template" "^7.18.10" "@babel/types" "^7.19.0" +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" @@ -160,6 +240,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-member-expression-to-functions@^7.20.7": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz#a6f26e919582275a93c3aa6594756d71b0bb7f05" @@ -174,6 +261,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11": version "7.20.11" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz#df4c7af713c557938c50ea3ad0117a7944b2f1b0" @@ -188,6 +282,20 @@ "@babel/traverse" "^7.20.10" "@babel/types" "^7.20.7" +"@babel/helper-module-transforms@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz#0f65daa0716961b6e96b164034e737f60a80d2ef" + integrity sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.5" + "@babel/types" "^7.22.5" + "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" @@ -229,6 +337,13 @@ dependencies: "@babel/types" "^7.20.2" +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers@^7.20.0": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" @@ -243,21 +358,43 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-split-export-declaration@^7.22.5", "@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.19.4": version "7.19.4" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + "@babel/helper-validator-option@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + "@babel/helper-wrap-function@^7.18.9": version "7.20.5" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz#75e2d84d499a0ab3b31c33bcfe59d6b8a45f62e3" @@ -277,6 +414,15 @@ "@babel/traverse" "^7.20.13" "@babel/types" "^7.20.7" +"@babel/helpers@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd" + integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -286,6 +432,20 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.14.7", "@babel/parser@^7.22.5", "@babel/parser@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.6.tgz#201f8b47be20c76c7c5743b9c16129760bf9a975" + integrity sha512-EIQu22vNkceq3LbjAq7knDf/UmtI2qbcNI8GRBlijez6TpQLvSodJPYfydQmNA5buwkxxxa/PVI44jjYZ+/cLw== + "@babel/parser@^7.20.13", "@babel/parser@^7.20.7": version "7.20.15" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.15.tgz#eec9f36d8eaf0948bb88c87a46784b5ee9fd0c89" @@ -860,6 +1020,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" +"@babel/polyfill@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" + integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + "@babel/preset-env@^7.16.11": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" @@ -989,10 +1157,17 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.20.13" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.13.tgz#7055ab8a7cff2b8f6058bf6ae45ff84ad2aded4b" - integrity sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" + integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/runtime@^7.12.13": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" + integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== dependencies: regenerator-runtime "^0.13.11" @@ -1005,6 +1180,15 @@ "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" +"@babel/template@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + "@babel/traverse@^7.20.10", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.13", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.4.5": version "7.20.13" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.13.tgz#817c1ba13d11accca89478bd5481b2d168d07473" @@ -1021,6 +1205,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.22.5", "@babel/traverse@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.6.tgz#8f2f83a5c588251584914debeee38f35f661a300" + integrity sha512-53CijMvKlLIDlOTrdWiHileRddlIiwUIyCKqYa7lYnnPldXCG5dUSN38uT0cA6i7rHWNKJLH0VU/Kxdr1GzB3w== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.6" + "@babel/types" "^7.22.5" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.4.4": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" @@ -1030,7 +1230,16 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@codemirror/autocomplete@^6.0.0", "@codemirror/autocomplete@^6.3.2", "@codemirror/autocomplete@^6.4.1": +"@babel/types@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" + integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@codemirror/autocomplete@^6.0.0", "@codemirror/autocomplete@^6.3.2": version "6.4.1" resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.4.1.tgz#0af405af8b90ab24bcb883d8218bd72e47ec03ec" integrity sha512-06yAmj0FjPZzYOpNeugJtG28GNqU2/CPr34m91Q+fKSyTOR6+hDFiatkPcIkxOlU0K5yP7WH6KoLg3fTqIUgaw== @@ -1040,16 +1249,37 @@ "@codemirror/view" "^6.6.0" "@lezer/common" "^1.0.0" +"@codemirror/autocomplete@^6.4.1": + version "6.4.2" + resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.4.2.tgz#938b25223bd21f97b2a6d85474643355f98b505b" + integrity sha512-8WE2xp+D0MpWEv5lZ6zPW1/tf4AGb358T5GWYiKEuCP8MvFfT3tH2mIF9Y2yr2e3KbHuSvsVhosiEyqCpiJhZQ== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.6.0" + "@lezer/common" "^1.0.0" + "@codemirror/commands@^6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.2.1.tgz#ab5e979ad1458bbe395bf69ac601f461ac73cf08" - integrity sha512-FFiNKGuHA5O8uC6IJE5apI5rT9gyjlw4whqy4vlcX0wE/myxL6P1s0upwDhY4HtMWLOwzwsp0ap3bjdQhvfDOA== + version "6.2.2" + resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.2.2.tgz#437d9ba275107dbc629f0bfa3b150e0e43f2a218" + integrity sha512-s9lPVW7TxXrI/7voZ+HmD/yiAlwAYn9PH5SUVSUhsxXHhv4yl5eZ3KLntSoTynfdgVYM0oIpccQEWRBQgmNZyw== dependencies: "@codemirror/language" "^6.0.0" "@codemirror/state" "^6.2.0" "@codemirror/view" "^6.0.0" "@lezer/common" "^1.0.0" +"@codemirror/lang-angular@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@codemirror/lang-angular/-/lang-angular-0.1.0.tgz#1054747c8196357a2aee2b9c36f0f6de9a6ffef9" + integrity sha512-vTjoHjzJmLrrMFmf/tojwp+O0P+R9mgWtjjaKDNDoY58PzOPg7ldMEBqIzABBc+/2mYPD85SG7O5byfBxc83eA== + dependencies: + "@codemirror/lang-html" "^6.0.0" + "@codemirror/lang-javascript" "^6.1.2" + "@codemirror/language" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/highlight" "^1.0.0" + "@codemirror/lang-cpp@^6.0.0": version "6.0.2" resolved "https://registry.yarnpkg.com/@codemirror/lang-cpp/-/lang-cpp-6.0.2.tgz#076c98340c3beabde016d7d83e08eebe17254ef9" @@ -1068,6 +1298,17 @@ "@codemirror/state" "^6.0.0" "@lezer/css" "^1.0.0" +"@codemirror/lang-css@^6.1.1", "@codemirror/lang-css@^6.2.0": + version "6.2.0" + resolved "https://registry.yarnpkg.com/@codemirror/lang-css/-/lang-css-6.2.0.tgz#f84f9da392099432445c75e32fdac63ae572315f" + integrity sha512-oyIdJM29AyRPM3+PPq1I2oIk8NpUfEN3kAM05XWDDs6o3gSneIKaVJifT2P+fqONLou2uIgXynFyMUDQvo/szA== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@lezer/common" "^1.0.2" + "@lezer/css" "^1.0.0" + "@codemirror/lang-html@^6.0.0": version "6.4.2" resolved "https://registry.yarnpkg.com/@codemirror/lang-html/-/lang-html-6.4.2.tgz#3c7117e45bae009bc7bc08eef8a79b5d05930d83" @@ -1104,6 +1345,19 @@ "@lezer/common" "^1.0.0" "@lezer/javascript" "^1.0.0" +"@codemirror/lang-javascript@^6.1.2": + version "6.1.7" + resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-6.1.7.tgz#e39fb9757b1cf47de432e4244d18ca5284a73a58" + integrity sha512-KXKqxlZ4W6t5I7i2ScmITUD3f/F5Cllk3kj0De9P9mFeYVfhOVOWuDLgYiLpk357u7Xh4dhqjJAnsNPPoTLghQ== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/language" "^6.6.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/javascript" "^1.0.0" + "@codemirror/lang-json@^6.0.0": version "6.0.1" resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-6.0.1.tgz#0a0be701a5619c4b0f8991f9b5e95fe33f462330" @@ -1112,7 +1366,17 @@ "@codemirror/language" "^6.0.0" "@lezer/json" "^1.0.0" -"@codemirror/lang-markdown@^6.0.0", "@codemirror/lang-markdown@^6.0.5": +"@codemirror/lang-less@^6.0.0": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@codemirror/lang-less/-/lang-less-6.0.1.tgz#fef10e8dbcd07055b815c3928233a05a8549181e" + integrity sha512-ABcsKBjLbyPZwPR5gePpc8jEKCQrFF4pby2WlMVdmJOOr7OWwwyz8DZonPx/cKDE00hfoSLc8F7yAcn/d6+rTQ== + dependencies: + "@codemirror/lang-css" "^6.2.0" + "@codemirror/language" "^6.0.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@codemirror/lang-markdown@^6.0.0": version "6.0.5" resolved "https://registry.yarnpkg.com/@codemirror/lang-markdown/-/lang-markdown-6.0.5.tgz#61393c7e2552528daee6aa4eca63428aa00832bd" integrity sha512-qH0THRYc2M7pIJoAp6jstXZkv8ZMVhNaBm7Bs4+0SLHhHlwX53txFy98AcPwrfq0Sh8Zi6RAuj9j/GyL8E1MKw== @@ -1124,6 +1388,18 @@ "@lezer/common" "^1.0.0" "@lezer/markdown" "^1.0.0" +"@codemirror/lang-markdown@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@codemirror/lang-markdown/-/lang-markdown-6.1.1.tgz#ff3cdd339c277f6a02d08eb12f1090977873e771" + integrity sha512-n87Ms6Y5UYb1UkFu8sRzTLfq/yyF1y2AYiWvaVdbBQi5WDj1tFk5N+AKA+WC0Jcjc1VxvrCCM0iizjdYYi9sFQ== + dependencies: + "@codemirror/lang-html" "^6.0.0" + "@codemirror/language" "^6.3.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/markdown" "^1.0.0" + "@codemirror/lang-php@^6.0.0": version "6.0.1" resolved "https://registry.yarnpkg.com/@codemirror/lang-php/-/lang-php-6.0.1.tgz#fa34cc75562178325861a5731f79bd621f57ffaa" @@ -1152,6 +1428,17 @@ "@codemirror/language" "^6.0.0" "@lezer/rust" "^1.0.0" +"@codemirror/lang-sass@^6.0.0": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@codemirror/lang-sass/-/lang-sass-6.0.1.tgz#e390f427c8601175f155046e142371c3c4fb718c" + integrity sha512-USy9zqtdLYxSuqq0s4peMoQi+BDzyOyO7chUzli+X2xVCjmBhc3CsWQ4kkDU0NYtCHHFQRkcFO8770eaOwZqfw== + dependencies: + "@codemirror/lang-css" "^6.1.1" + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@lezer/common" "^1.0.2" + "@lezer/sass" "^1.0.0" + "@codemirror/lang-sql@^6.0.0": version "6.4.0" resolved "https://registry.yarnpkg.com/@codemirror/lang-sql/-/lang-sql-6.4.0.tgz#f9303e511fb9511884f90043e354d5df3bd4b032" @@ -1163,6 +1450,18 @@ "@lezer/highlight" "^1.0.0" "@lezer/lr" "^1.0.0" +"@codemirror/lang-vue@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@codemirror/lang-vue/-/lang-vue-0.1.1.tgz#79567fb3be3f411354cd135af59d67f956cdb042" + integrity sha512-GIfc/MemCFKUdNSYGTFZDN8XsD2z0DUY7DgrK34on0dzdZ/CawZbi+SADYfVzWoPPdxngHzLhqlR5pSOqyPCvA== + dependencies: + "@codemirror/lang-html" "^6.0.0" + "@codemirror/lang-javascript" "^6.1.2" + "@codemirror/language" "^6.0.0" + "@lezer/common" "^1.0.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.3.1" + "@codemirror/lang-wast@^6.0.0": version "6.0.1" resolved "https://registry.yarnpkg.com/@codemirror/lang-wast/-/lang-wast-6.0.1.tgz#c15bec84548a5e9b0a43fa69fb63631d087d6047" @@ -1183,22 +1482,26 @@ "@lezer/common" "^1.0.0" "@lezer/xml" "^1.0.0" -"@codemirror/language-data@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@codemirror/language-data/-/language-data-6.1.0.tgz#479eff66289a6453493f7c8213d7b2ceb95c89f6" - integrity sha512-g9V23fuLRI9AEbpM6bDy1oquqgpFlIDHTihUhL21NPmxp+x67ZJbsKk+V71W7/Bj8SCqEO1PtqQA/tDGgt1nfw== +"@codemirror/language-data@^6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@codemirror/language-data/-/language-data-6.3.1.tgz#795ec09e04260868070296241363d70f4060bb36" + integrity sha512-p6jhJmvhGe1TG1EGNhwH7nFWWFSTJ8NDKnB2fVx5g3t+PpO0+63R7GJNxjS0TmmH3cdMxZbzejsik+rlEh1EyQ== dependencies: + "@codemirror/lang-angular" "^0.1.0" "@codemirror/lang-cpp" "^6.0.0" "@codemirror/lang-css" "^6.0.0" "@codemirror/lang-html" "^6.0.0" "@codemirror/lang-java" "^6.0.0" "@codemirror/lang-javascript" "^6.0.0" "@codemirror/lang-json" "^6.0.0" + "@codemirror/lang-less" "^6.0.0" "@codemirror/lang-markdown" "^6.0.0" "@codemirror/lang-php" "^6.0.0" "@codemirror/lang-python" "^6.0.0" "@codemirror/lang-rust" "^6.0.0" + "@codemirror/lang-sass" "^6.0.0" "@codemirror/lang-sql" "^6.0.0" + "@codemirror/lang-vue" "^0.1.1" "@codemirror/lang-wast" "^6.0.0" "@codemirror/lang-xml" "^6.0.0" "@codemirror/language" "^6.0.0" @@ -1223,7 +1526,7 @@ dependencies: "@codemirror/language" "^6.0.0" -"@codemirror/lint@^6.0.0", "@codemirror/lint@^6.1.0": +"@codemirror/lint@^6.0.0": version "6.1.1" resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.1.1.tgz#b30741e714a43a11cb78feb2c220b4971ad175f3" integrity sha512-e+M543x0NVHGayNHQzLP4XByJsvbu/ojY6+0VF2Y4Uu66Rt1nADuxNflZwECLf7gS009smIsptSUa6bUj/U/rw== @@ -1232,10 +1535,19 @@ "@codemirror/view" "^6.0.0" crelt "^1.0.5" +"@codemirror/lint@^6.1.0": + version "6.2.0" + resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.2.0.tgz#25cdab7425fcda1b38a9d63f230f833c8b6b369f" + integrity sha512-KVCECmR2fFeYBr1ZXDVue7x3q5PMI0PzcIbA+zKufnkniMBo1325t0h1jM85AKp8l3tj67LRxVpZfgDxEXlQkg== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" + "@codemirror/search@^6.2.3": - version "6.2.3" - resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.2.3.tgz#fab933fef1b1de8ef40cda275c73d9ac7a1ff40f" - integrity sha512-V9n9233lopQhB1dyjsBK2Wc1i+8hcCqxl1wQ46c5HWWLePoe4FluV3TGHoZ04rBRlGjNyz9DTmpJErig8UE4jw== + version "6.3.0" + resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.3.0.tgz#d48b2d636fc7474613e240ba8e56c4c5e6e51822" + integrity sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw== dependencies: "@codemirror/state" "^6.0.0" "@codemirror/view" "^6.0.0" @@ -1246,10 +1558,19 @@ resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.2.0.tgz#a0fb08403ced8c2a68d1d0acee926bd20be922f2" integrity sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA== -"@codemirror/view@^6.0.0", "@codemirror/view@^6.2.2", "@codemirror/view@^6.6.0", "@codemirror/view@^6.9.0": - version "6.9.0" - resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.9.0.tgz#39116d84523884198d000153a8cc24ca6a28f2b9" - integrity sha512-uFaqE6fBOp0Dj/tmWoe/TFlSSIPdpAzhvATgbq1eAKRkgq3hY79FioZ7nfdiT+24kz68AIWuSZ9hi3psKe36WQ== +"@codemirror/view@^6.0.0", "@codemirror/view@^6.6.0", "@codemirror/view@^6.9.0": + version "6.9.3" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.9.3.tgz#4475dc0ff5d9a55f8144ad7484e7e17416861cce" + integrity sha512-BJ5mvEIhFM+SrNwc5X8pLIvMM9ffjkviVbxpg84Xk2OE8ZyKaEbId8kX+nAYEEso7+qnbwsXe1bkAHsasebMow== + dependencies: + "@codemirror/state" "^6.1.4" + style-mod "^4.0.0" + w3c-keyname "^2.2.4" + +"@codemirror/view@^6.2.2": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.7.1.tgz#370e95d6f001e7f5cadc459807974b4f0a6eb225" + integrity sha512-kYtS+uqYw/q/0ytYxpkqE1JVuK5NsbmBklWYhwLFTKO9gVuTdh/kDEeZPKorbqHcJ+P+ucrhcsS1czVweOpT2g== dependencies: "@codemirror/state" "^6.1.4" style-mod "^4.0.0" @@ -1260,6 +1581,246 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@csstools/cascade-layer-name-parser@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.1.tgz#5957adeb71be8159e543d37a9c48e124dcd6c32e" + integrity sha512-SAAi5DpgJJWkfTvWSaqkgyIsTawa83hMwKrktkj6ra2h+q6ZN57vOGZ6ySHq6RSo+CbP64fA3aPChPBRDDUgtw== + +"@csstools/color-helpers@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-1.0.0.tgz#7097722a51da1e9e622345ca000261f1ae6e8f58" + integrity sha512-tgqtiV8sU/VaWYjOB3O7PWs7HR/MmOLl2kTYRW2qSsTSEniJq7xmyAYFB1LPpXvvQcE5u2ih2dK9fyc8BnrAGQ== + +"@csstools/color-helpers@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-2.0.0.tgz#4ac578cb00b4e853b94f2250267d85ba957c4fc9" + integrity sha512-VcPjEnp07RNgz/D+oI2uIALg+IPCSl6mj0XhA3pl3F2bM2B95vgzatExmmzSg/X0zkh+R2v+jFY/J2pV/bnwpw== + +"@csstools/css-calc@^1.0.0", "@csstools/css-calc@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-1.0.1.tgz#c478dbfb2c10e22741b261b2a64998960d69bfc7" + integrity sha512-VBI8X0bmStfc85wWTa2bsbnlBQxgW4FmJ0Ts9ar9UqytE6kii3yg6GO+wpgzht2oK5Qlbpkm1Fy2kcqVmu6f3Q== + +"@csstools/css-color-parser@^1.0.0", "@csstools/css-color-parser@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-1.1.0.tgz#717d544aa5c5f77e3fb71e77f1500338c1ee7436" + integrity sha512-jRpIhjThaH8jxuJ8Q1H+jai/dekP5952kzLHTuN+rPI48eF2esf/18TMb3N/HtEgmnybhfiwUO6Ph2OkHi3jpA== + dependencies: + "@csstools/color-helpers" "^2.0.0" + "@csstools/css-calc" "^1.0.1" + +"@csstools/css-parser-algorithms@^2.0.0", "@csstools/css-parser-algorithms@^2.0.1", "@csstools/css-parser-algorithms@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.1.0.tgz#c0a605b0218790faeb5911f240964891c6031501" + integrity sha512-KP8TicdXpUyeB1NMlbHud/1l39xvLGvqNFWMpG4qC6H1zs9SadGUHe5SO92n/659sDW9aGDvm9AMru0DZkN1Bw== + +"@csstools/css-tokenizer@^2.0.0", "@csstools/css-tokenizer@^2.0.1", "@csstools/css-tokenizer@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-2.1.0.tgz#fee4de3d444db3ce9007f3af6474af8ba3e4b930" + integrity sha512-dtqFyoJBHUxGi9zPZdpCKP1xk8tq6KPHJ/NY4qWXiYo6IcSGwzk3L8x2XzZbbyOyBs9xQARoGveU2AsgLj6D2A== + +"@csstools/media-query-list-parser@^2.0.0", "@csstools/media-query-list-parser@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.0.2.tgz#36058f8ff6a28274e7dfe32e48431e1de97c2fbb" + integrity sha512-8V6JD8Av1HttuClYr1ZBu0LRVe5Nnz4qrv8RppO8mobsX/USBHZy5JQOXYIlpOVhl46nzkx3X5cfH6CqUghjrQ== + +"@csstools/postcss-cascade-layers@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-3.0.1.tgz#d839386e90428b448e3f75276bc01d516e852a0d" + integrity sha512-dD8W98dOYNOH/yX4V4HXOhfCOnvVAg8TtsL+qCGNoKXuq5z2C/d026wGWgySgC8cajXXo/wNezS31Glj5GcqrA== + dependencies: + "@csstools/selector-specificity" "^2.0.2" + postcss-selector-parser "^6.0.10" + +"@csstools/postcss-color-function@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-2.2.0.tgz#b9251d5dd13e56c5893a220c32008ac5af4b009f" + integrity sha512-4z3k3p35Gmv4ZDX79OytvhwYx6Hz+y3hitikw2F+XG1yhSjalXoMCV04atgLjc/ThLg+Hwnp1pxhQ2G07UHknQ== + dependencies: + "@csstools/css-color-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.1" + "@csstools/css-tokenizer" "^2.1.0" + "@csstools/postcss-progressive-custom-properties" "^2.0.0" + +"@csstools/postcss-color-mix-function@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-1.0.0.tgz#8d65782527eefc7228ea6fb9b6fa936e52b9b4ad" + integrity sha512-JuI8SKpE/XIpfmvALcxvk6flaq36KCJwqQgZ958Jz189r1diQZADq+7xFmjcv+B0vHQ4nSa92gGExtzOZ1iiUg== + dependencies: + "@csstools/css-color-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.1" + "@csstools/css-tokenizer" "^2.1.0" + "@csstools/postcss-progressive-custom-properties" "^2.0.0" + +"@csstools/postcss-font-format-keywords@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-2.0.2.tgz#d798d96f4af6cddcfee459f598c976e6011042d2" + integrity sha512-iKYZlIs6JsNT7NKyRjyIyezTCHLh4L4BBB3F5Nx7Dc4Z/QmBgX+YJFuUSar8IM6KclGiAUFGomXFdYxAwJydlA== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-gradients-interpolation-method@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-3.0.1.tgz#e5237dd765f951c1f4b113d29c4bd2438db5dc33" + integrity sha512-sCfFSzL5HRb/GhrGuTEi8IRrxp2bUeKakyXvuXzuBBxL0L2X8kZAljQwkuRkd0W/wIWTsQG/E72REb5XMmRfrA== + dependencies: + "@csstools/css-color-parser" "^1.1.0" + "@csstools/css-parser-algorithms" "^2.1.0" + "@csstools/css-tokenizer" "^2.1.0" + "@csstools/postcss-progressive-custom-properties" "^2.0.0" + +"@csstools/postcss-hwb-function@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-2.2.0.tgz#80ee5780b88994b1128ad67f98d468798413b7d7" + integrity sha512-7gDPKacr3KhonzEyj4dzAEcetFJbN+JVPZXtANpf9SAVUHDUK+cCw7367uRlXnCeAoTdmRAyBk3agg2+snFxAw== + dependencies: + "@csstools/css-color-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.1" + "@csstools/css-tokenizer" "^2.1.0" + +"@csstools/postcss-ic-unit@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-2.0.2.tgz#5a5e481c53977deec3d63793788eec924d4c5f7d" + integrity sha512-N84qGTJkfLTPj2qOG5P4CIqGjpZBbjOEMKMn+UjO5wlb9lcBTfBsxCF0lQsFdWJUzBHYFOz19dL66v71WF3Pig== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^2.0.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-is-pseudo-class@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-3.1.1.tgz#81b0f3ba388bf3c8966e1a4413e1839beef7960e" + integrity sha512-hhiacuby4YdUnnxfCYCRMBIobyJImozf0u+gHSbQ/tNOdwvmrZtVROvgW7zmfYuRkHVDNZJWZslq2v5jOU+j/A== + dependencies: + "@csstools/selector-specificity" "^2.0.0" + postcss-selector-parser "^6.0.10" + +"@csstools/postcss-logical-float-and-clear@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-1.0.1.tgz#d255ea7aad18880930b63d8a04164f56182f2ecf" + integrity sha512-eO9z2sMLddvlfFEW5Fxbjyd03zaO7cJafDurK4rCqyRt9P7aaWwha0LcSzoROlcZrw1NBV2JAp2vMKfPMQO1xw== + +"@csstools/postcss-logical-resize@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-resize/-/postcss-logical-resize-1.0.1.tgz#826d3de929d7d786c32c2c118f78e813a1c2cdec" + integrity sha512-x1ge74eCSvpBkDDWppl+7FuD2dL68WP+wwP2qvdUcKY17vJksz+XoE1ZRV38uJgS6FNUwC0AxrPW5gy3MxsDHQ== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-logical-viewport-units@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-1.0.2.tgz#b968c57e1459429b48b24e2c250ca0904d71df6e" + integrity sha512-nnKFywBqRMYjv5jyjSplD/nbAnboUEGFfdxKw1o34Y1nvycgqjQavhKkmxbORxroBBIDwC5y6SfgENcPPUcOxQ== + dependencies: + "@csstools/css-tokenizer" "^2.0.0" + +"@csstools/postcss-media-minmax@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.0.0.tgz#c9978e3ae65b389d149f66cf0c266b2627cd2ec5" + integrity sha512-qXHZ0QVDszKf4SsLazOEzFl+m+IkhHOigqMy/gHNIzAtqB3XeBQUa+dTi1ROmQBDH1HXktGwy+tafFBg9UoaxA== + dependencies: + "@csstools/css-calc" "^1.0.1" + "@csstools/css-parser-algorithms" "^2.1.0" + "@csstools/css-tokenizer" "^2.1.0" + "@csstools/media-query-list-parser" "^2.0.2" + +"@csstools/postcss-media-queries-aspect-ratio-number-values@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-1.0.1.tgz#fd6a8e50c2d6d46a5c95b6cdc5563a091fa2f0fa" + integrity sha512-V9yQqXdje6OfqDf6EL5iGOpi6N0OEczwYK83rql9UapQwFEryXlAehR5AqH8QqLYb6+y31wUXK6vMxCp0920Zg== + dependencies: + "@csstools/css-parser-algorithms" "^2.0.0" + "@csstools/css-tokenizer" "^2.0.0" + "@csstools/media-query-list-parser" "^2.0.0" + +"@csstools/postcss-nested-calc@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-nested-calc/-/postcss-nested-calc-2.0.2.tgz#a0857650ef88b1aa7b094c7ea8ea1378c35695e0" + integrity sha512-jbwrP8rN4e7LNaRcpx3xpMUjhtt34I9OV+zgbcsYAAk6k1+3kODXJBf95/JMYWhu9g1oif7r06QVUgfWsKxCFw== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-normalize-display-values@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-2.0.1.tgz#35dc188c5b4713cf902959fe3c8ce613fcb7543e" + integrity sha512-TQT5g3JQ5gPXC239YuRK8jFceXF9d25ZvBkyjzBGGoW5st5sPXFVQS8OjYb9IJ/K3CdfK4528y483cgS2DJR/w== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-oklab-function@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-2.2.0.tgz#4f9c91736316eb881d932681ae566a38af554a39" + integrity sha512-5QMtgn9IWpeTbbt8DwLvr41CQRJef2fKhznTFQI1Og/v3zr/uKYu+aSKZEEaoZnO9OophM4YJnkVJne3CqvJDQ== + dependencies: + "@csstools/css-color-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.1" + "@csstools/css-tokenizer" "^2.1.0" + "@csstools/postcss-progressive-custom-properties" "^2.0.0" + +"@csstools/postcss-progressive-custom-properties@^2.0.0", "@csstools/postcss-progressive-custom-properties@^2.1.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-2.1.1.tgz#82df9314451db63bf7f4975a4d32f148e85db490" + integrity sha512-6p8eO5+j+9hn4h2Klr9dbmya0GIb9SRrnPaCxqR1muVlV1waAZq6YkmlApEwXrox9qxggSwGZD5TnLRIY9f7WA== + dependencies: + postcss-value-parser "^4.2.0" + +"@csstools/postcss-scope-pseudo-class@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-2.0.2.tgz#6325e1e3b321093c59b008ec670bb772e17f06fe" + integrity sha512-6Pvo4uexUCXt+Hz5iUtemQAcIuCYnL+ePs1khFR6/xPgC92aQLJ0zGHonWoewiBE+I++4gXK3pr+R1rlOFHe5w== + dependencies: + postcss-selector-parser "^6.0.10" + +"@csstools/postcss-stepped-value-functions@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-2.1.0.tgz#8ca134a7f70e00b14f5796fb32ed33a656ba0b1b" + integrity sha512-CkEo9BF8fQeMoXW3biXjlgTLY7PA4UFihn6leq7hPoRzIguLUI0WZIVgsITGXfX8LXmkhCSTjXO2DLYu/LUixQ== + dependencies: + "@csstools/css-calc" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.1" + "@csstools/css-tokenizer" "^2.0.1" + +"@csstools/postcss-text-decoration-shorthand@^2.2.1": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-2.2.2.tgz#75539827b56905f7c2e8273c0358cc6fec5ca72d" + integrity sha512-aR9l/V7p0SkdrIyBysqlQWIbGXeGC7U4ccBAIlWMpVpG/MsGhxs1JvdBpjim4UDF3U+1VmF+MbvZFb7dL+d7XA== + dependencies: + "@csstools/color-helpers" "^1.0.0" + postcss-value-parser "^4.2.0" + +"@csstools/postcss-trigonometric-functions@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-2.1.0.tgz#5a489975d445b9e79c6cb5f0f01ae711ec86639d" + integrity sha512-Ly7YczO+QdnByYeGqlppJoA2Tb2vsFfj5gSrszPTXJ+/4g3nnEZnG0VSeTK/WA8y7fzyL/qVNkkdEeOnruNWFQ== + dependencies: + "@csstools/css-calc" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.1" + "@csstools/css-tokenizer" "^2.0.1" + +"@csstools/postcss-unset-value@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@csstools/postcss-unset-value/-/postcss-unset-value-2.0.1.tgz#67091dd6cff556bff896c95053eb070cc6b21c25" + integrity sha512-oJ9Xl29/yU8U7/pnMJRqAZd4YXNCfGEdcP4ywREuqm/xMqcgDNDppYRoCGDt40aaZQIEKBS79LytUDN/DHf0Ew== + +"@csstools/selector-specificity@^2.0.0", "@csstools/selector-specificity@^2.0.1", "@csstools/selector-specificity@^2.0.2": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016" + integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== + +"@cypress/code-coverage@^3.10.8": + version "3.10.8" + resolved "https://registry.yarnpkg.com/@cypress/code-coverage/-/code-coverage-3.10.8.tgz#f6849e5dfe3badb4c4534cd7ecc8a8b571c4ce2c" + integrity sha512-9KZvQKYjoz09ocZEGC0a0+uVFSMe6gOblqGpWoTGi8HYSbKFAuOJkjJB5vJ1fb1u52GOgW2b1JqhhtJJyA/ksg== + dependencies: + "@cypress/webpack-preprocessor" "^5.11.0" + chalk "4.1.2" + dayjs "1.11.8" + debug "4.3.4" + execa "4.1.0" + globby "11.0.4" + istanbul-lib-coverage "3.0.0" + js-yaml "4.1.0" + nyc "15.1.0" + "@cypress/request@^2.88.10": version "2.88.11" resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.11.tgz#5a4c7399bc2d7e7ed56e92ce5acb620c8b187047" @@ -1284,6 +1845,15 @@ tunnel-agent "^0.6.0" uuid "^8.3.2" +"@cypress/webpack-preprocessor@^5.11.0": + version "5.17.1" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.17.1.tgz#19c3f6ceb89e156824917b4ec31717ade34592ec" + integrity sha512-FE/e8ikPc8z4EVopJCaior3RGy0jd2q9Xcp5NtiwNG4XnLfEnUFTZlAGwXe75sEh4fNMPrBJW1KIz77PX5vGAw== + dependencies: + bluebird "3.7.1" + debug "^4.3.4" + lodash "^4.17.20" + "@cypress/xvfb@^1.2.4": version "1.2.4" resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" @@ -1348,7 +1918,24 @@ source-map "^0.5.7" stylis "4.1.3" -"@emotion/cache@^11.10.5": +"@emotion/babel-plugin@^11.10.6": + version "11.10.6" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz#a68ee4b019d661d6f37dec4b8903255766925ead" + integrity sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/serialize" "^1.1.1" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.1.3" + +"@emotion/cache@^11.10.5", "@emotion/cache@^11.4.0": version "11.10.5" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12" integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA== @@ -1359,10 +1946,16 @@ "@emotion/weak-memoize" "^0.3.0" stylis "4.1.3" -"@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== +"@emotion/cache@^11.10.8": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" + integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== + dependencies: + "@emotion/memoize" "^0.8.1" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + stylis "4.2.0" "@emotion/hash@^0.9.0": version "0.9.0" @@ -1381,6 +1974,11 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== +"@emotion/memoize@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" + integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== + "@emotion/react@^11.7.1": version "11.10.5" resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.5.tgz#95fff612a5de1efa9c0d535384d3cfa115fe175d" @@ -1395,6 +1993,20 @@ "@emotion/weak-memoize" "^0.3.0" hoist-non-react-statics "^3.3.1" +"@emotion/react@^11.8.1": + version "11.10.6" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.6.tgz#dbe5e650ab0f3b1d2e592e6ab1e006e75fd9ac11" + integrity sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.6" + "@emotion/cache" "^11.10.5" + "@emotion/serialize" "^1.1.1" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + hoist-non-react-statics "^3.3.1" + "@emotion/serialize@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0" @@ -1411,6 +2023,11 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c" integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== +"@emotion/sheet@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" + integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== + "@emotion/styled@^11.6.0": version "11.10.5" resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.5.tgz#1fe7bf941b0909802cb826457e362444e7e96a79" @@ -1448,11 +2065,21 @@ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== +"@emotion/utils@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" + integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== + "@emotion/weak-memoize@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== +"@emotion/weak-memoize@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" + integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== + "@eslint/eslintrc@^1.4.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" @@ -1468,6 +2095,90 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@floating-ui/core@^1.2.4": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.5.tgz#612f0d203e6f647490d572c7b798eebac9e3cf54" + integrity sha512-qrcbyfnRVziRlB6IYwjCopYhO7Vud750JlJyuljruIXcPxr22y8zdckcJGsuOdnQ639uVD1tTXddrcH3t3QYIQ== + +"@floating-ui/core@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.3.0.tgz#113bc85fa102cf890ae801668f43ee265c547a09" + integrity sha512-vX1WVAdPjZg9DkDkC+zEx/tKtnST6/qcNpwcjeBgco3XRNHz5PUA+ivi/yr6G3o0kMR60uKBJcfOdfzOFI7PMQ== + +"@floating-ui/dom@^1.0.1": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.5.tgz#c9ec259a24ce0958b1ea29674df4eee4455361a9" + integrity sha512-+sAUfpQ3Frz+VCbPCqj+cZzvEESy3fjSeT/pDWkYCWOBXYNNKZfuVsHuv8/JO2zze8+Eb/Q7a6hZVgzS81fLbQ== + dependencies: + "@floating-ui/core" "^1.2.4" + +"@floating-ui/dom@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.3.0.tgz#69456f2164fc3d33eb40837686eaf71537235ac9" + integrity sha512-qIAwejE3r6NeA107u4ELDKkH8+VtgRKdXqtSPaKflL2S2V+doyN+Wt9s5oHKXPDo4E8TaVXaHT3+6BbagH31xw== + dependencies: + "@floating-ui/core" "^1.3.0" + +"@floating-ui/react-dom@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.1.tgz#7972a4fc488a8c746cded3cfe603b6057c308a91" + integrity sha512-rZtAmSht4Lry6gdhAJDrCp/6rKN7++JnL1/Anbr/DdeyYXQPxvg/ivrbYvJulbRf4vL8b212suwMM2lxbv+RQA== + dependencies: + "@floating-ui/dom" "^1.3.0" + +"@floating-ui/react@^0.24.2": + version "0.24.3" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.24.3.tgz#4f11f09c7245555724f5167dd6925133457db89c" + integrity sha512-wWC9duiog4HmbgKSKObDRuXqMjZR/6m75MIG+slm5CVWbridAjK9STcnCsGYmdpK78H/GmzYj4ADVP8paZVLYQ== + dependencies: + "@floating-ui/react-dom" "^2.0.1" + aria-hidden "^1.1.3" + tabbable "^6.0.1" + +"@formatjs/ecma402-abstract@1.17.0": + version "1.17.0" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz#2ce191a3bde4c65c6684e03fa247062a4a294b9e" + integrity sha512-6ueQTeJZtwKjmh23bdkq/DMqH4l4bmfvtQH98blOSbiXv/OUiyijSW6jU22IT8BNM1ujCaEvJfTtyCYVH38EMQ== + dependencies: + "@formatjs/intl-localematcher" "0.4.0" + tslib "^2.4.0" + +"@formatjs/fast-memoize@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz#33bd616d2e486c3e8ef4e68c99648c196887802b" + integrity sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA== + dependencies: + tslib "^2.4.0" + +"@formatjs/icu-messageformat-parser@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.0.tgz#b0d58ce8c8f472969c96b5cd0b3ad5522d3a02b7" + integrity sha512-yT6at0qc0DANw9qM/TU8RZaCtfDXtj4pZM/IC2WnVU80yAcliS3KVDiuUt4jSQAeFL9JS5bc2hARnFmjPdA6qw== + dependencies: + "@formatjs/ecma402-abstract" "1.17.0" + "@formatjs/icu-skeleton-parser" "1.6.0" + tslib "^2.4.0" + +"@formatjs/icu-skeleton-parser@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.0.tgz#0728be8b6b3656f1a4b8e6e5b0e02dffffc23c6c" + integrity sha512-eMmxNpoX/J1IPUjPGSZwo0Wh+7CEvdEMddP2Jxg1gQJXfGfht/FdW2D5XDFj3VMbOTUQlDIdZJY7uC6O6gjPoA== + dependencies: + "@formatjs/ecma402-abstract" "1.17.0" + tslib "^2.4.0" + +"@formatjs/intl-localematcher@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.4.0.tgz#63bbc37a7c3545a1bf1686072e51d9a3aed98d6b" + integrity sha512-bRTd+rKomvfdS4QDlVJ6TA/Jx1F2h/TBVO5LjvhQ7QPPHp19oPNMIum7W2CMEReq/zPxpmCeB31F9+5gl/qtvw== + dependencies: + tslib "^2.4.0" + +"@heroicons/react@2.0.13": + version "2.0.13" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.13.tgz#9b1cc54ff77d6625c9565efdce0054a4bcd9074c" + integrity sha512-iSN5XwmagrnirWlYEWNPdCDj9aRYVD/lnK3JlsC9/+fqGF80k8C7rl+1HCvBX0dBoagKqOFBs6fMhJJ1hOg1EQ== + "@humanwhocodes/config-array@^0.11.8": version "0.11.8" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" @@ -1487,10 +2198,50 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@icons/material@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" - integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== +"@internationalized/date@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.2.0.tgz#1d266e5e5543a059cf8cca9b954fa033c3e58a75" + integrity sha512-VDMHN1m33L4eqPs5BaihzgQJXyaORbMoHOtrapFxx179J8ucY5CRIHYsq5RRLKPHZWgjNfa5v6amWWDkkMFywA== + dependencies: + "@swc/helpers" "^0.4.14" + +"@internationalized/message@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.0.tgz#b284014cd8bbb430a648b76c87c62bdca968b04c" + integrity sha512-Oo5m70FcBdADf7G8NkUffVSfuCdeAYVfsvNjZDi9ELpjvkc4YNJVTHt/NyTI9K7FgAVoELxiP9YmN0sJ+HNHYQ== + dependencies: + "@swc/helpers" "^0.4.14" + intl-messageformat "^10.1.0" + +"@internationalized/number@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.2.0.tgz#dffb661cacd61a87b814c47b7d5240a286249066" + integrity sha512-GUXkhXSX1Ee2RURnzl+47uvbOxnlMnvP9Er+QePTjDjOPWuunmLKlEkYkEcLiiJp7y4l9QxGDLOlVr8m69LS5w== + dependencies: + "@swc/helpers" "^0.4.14" + +"@internationalized/string@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.1.0.tgz#0b365906a8c3f44800b0db52c2e990cff345abce" + integrity sha512-TJQKiyUb+wyAfKF59UNeZ/kELMnkxyecnyPCnBI1ma4NaXReJW+7Cc2mObXAqraIBJUVv7rgI46RLKrLgi35ng== + dependencies: + "@swc/helpers" "^0.4.14" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== "@jest/expect-utils@^29.4.3": version "29.4.3" @@ -1566,12 +2317,20 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/trace-mapping@^0.3.17": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== -"@lezer/common@^1.0.0": +"@lezer/common@^1.0.0", "@lezer/common@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.0.2.tgz#8fb9b86bdaa2ece57e7d59e5ffbcb37d71815087" integrity sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng== @@ -1593,9 +2352,9 @@ "@lezer/lr" "^1.0.0" "@lezer/highlight@^1.0.0", "@lezer/highlight@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.1.3.tgz#bf5a36c2ee227f526d74997ac91f7777e29bd25d" - integrity sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw== + version "1.1.4" + resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.1.4.tgz#98ed821e89f72981b7ba590474e6ee86c8185619" + integrity sha512-IECkFmw2l7sFcYXrV8iT9GeY4W0fU4CxX0WMwhmhMIVjoDdD1Hr6q3G2NqVtLg/yVe5n7i4menG3tJ2r4eCrPQ== dependencies: "@lezer/common" "^1.0.0" @@ -1639,6 +2398,13 @@ dependencies: "@lezer/common" "^1.0.0" +"@lezer/lr@^1.3.1": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.3.4.tgz#8795bf2ba4f69b998e8fb4b5a7c57ea68753474c" + integrity sha512-7o+e4og/QoC/6btozDPJqnzBhUaD1fMfmvnEKQO1wRRiTse1WxaJ3OMEXZJnkgT6HCcTVOctSoXK9jGJw2oe9g== + dependencies: + "@lezer/common" "^1.0.0" + "@lezer/markdown@^1.0.0": version "1.0.2" resolved "https://registry.yarnpkg.com/@lezer/markdown/-/markdown-1.0.2.tgz#8c804a9f6fe1ccca4a20acd2fd9fbe0fae1ae178" @@ -1671,6 +2437,14 @@ "@lezer/highlight" "^1.0.0" "@lezer/lr" "^1.0.0" +"@lezer/sass@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@lezer/sass/-/sass-1.0.1.tgz#c0ec3ece28b04e92437a75ac4a806367e5cb6fd4" + integrity sha512-S/aYAzABzMqWLfKKqV89pCWME4yjZYC6xzD02l44wbmb0sHxmN9/8aE4GULrKFzFaGazHdXcGEbPZ4zzB6yqwQ== + dependencies: + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + "@lezer/xml@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@lezer/xml/-/xml-1.0.1.tgz#c4c738a407db610f0e9c59d0e9b16607cd029591" @@ -1679,164 +2453,112 @@ "@lezer/highlight" "^1.0.0" "@lezer/lr" "^1.0.0" -"@material-ui/core@^4.12.4": - version "4.12.4" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.4.tgz#4ac17488e8fcaf55eb6a7f5efb2a131e10138a73" - integrity sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/styles" "^4.11.5" - "@material-ui/system" "^4.12.2" - "@material-ui/types" "5.1.0" - "@material-ui/utils" "^4.11.3" - "@types/react-transition-group" "^4.2.0" - clsx "^1.0.4" - hoist-non-react-statics "^3.3.2" - popper.js "1.16.1-lts" - prop-types "^15.7.2" - react-is "^16.8.0 || ^17.0.0" - react-transition-group "^4.4.0" - -"@material-ui/icons@^4.11.3": - version "4.11.3" - resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.11.3.tgz#b0693709f9b161ce9ccde276a770d968484ecff1" - integrity sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA== - dependencies: - "@babel/runtime" "^7.4.4" - -"@material-ui/lab@^4.0.0-alpha.60": - version "4.0.0-alpha.61" - resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz#9bf8eb389c0c26c15e40933cc114d4ad85e3d978" - integrity sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/utils" "^4.11.3" - clsx "^1.0.4" - prop-types "^15.7.2" - react-is "^16.8.0 || ^17.0.0" - -"@material-ui/styles@^4.11.4", "@material-ui/styles@^4.11.5", "@material-ui/styles@^4.8.2": - version "4.11.5" - resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.11.5.tgz#19f84457df3aafd956ac863dbe156b1d88e2bbfb" - integrity sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA== - dependencies: - "@babel/runtime" "^7.4.4" - "@emotion/hash" "^0.8.0" - "@material-ui/types" "5.1.0" - "@material-ui/utils" "^4.11.3" - clsx "^1.0.4" - csstype "^2.5.2" - hoist-non-react-statics "^3.3.2" - jss "^10.5.1" - jss-plugin-camel-case "^10.5.1" - jss-plugin-default-unit "^10.5.1" - jss-plugin-global "^10.5.1" - jss-plugin-nested "^10.5.1" - jss-plugin-props-sort "^10.5.1" - jss-plugin-rule-value-function "^10.5.1" - jss-plugin-vendor-prefixer "^10.5.1" - prop-types "^15.7.2" - -"@material-ui/system@^4.12.2": - version "4.12.2" - resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.2.tgz#f5c389adf3fce4146edd489bf4082d461d86aa8b" - integrity sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw== - dependencies: - "@babel/runtime" "^7.4.4" - "@material-ui/utils" "^4.11.3" - csstype "^2.5.2" - prop-types "^15.7.2" - -"@material-ui/types@5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2" - integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A== - -"@material-ui/utils@^4.11.3": - version "4.11.3" - resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.11.3.tgz#232bd86c4ea81dab714f21edad70b7fdf0253942" - integrity sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg== - dependencies: - "@babel/runtime" "^7.4.4" - prop-types "^15.7.2" - react-is "^16.8.0 || ^17.0.0" - -"@mui/base@5.0.0-alpha.118": - version "5.0.0-alpha.118" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.118.tgz#335e7496ea605c9b7bda4164efb2da3f09f36dfc" - integrity sha512-GAEpqhnuHjRaAZLdxFNuOf2GDTp9sUawM46oHZV4VnYPFjXJDkIYFWfIQLONb0nga92OiqS5DD/scGzVKCL0Mw== +"@mui/base@5.0.0-alpha.128": + version "5.0.0-alpha.128" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.128.tgz#8ce4beb971ac989df0b1d3b2bd3e9274dbfa604f" + integrity sha512-wub3wxNN+hUp8hzilMlXX3sZrPo75vsy1cXEQpqdTfIFlE9HprP1jlulFiPg5tfPst2OKmygXr2hhmgvAKRrzQ== dependencies: - "@babel/runtime" "^7.20.13" + "@babel/runtime" "^7.21.0" "@emotion/is-prop-valid" "^1.2.0" - "@mui/types" "^7.2.3" - "@mui/utils" "^5.11.9" - "@popperjs/core" "^2.11.6" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.12.3" + "@popperjs/core" "^2.11.7" clsx "^1.2.1" prop-types "^15.8.1" react-is "^18.2.0" -"@mui/core-downloads-tracker@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.9.tgz#0d3b20c2ef7704537c38597f9ecfc1894fe7c367" - integrity sha512-YGEtucQ/Nl91VZkzYaLad47Cdui51n/hW+OQm4210g4N3/nZzBxmGeKfubEalf+ShKH4aYDS86XTO6q/TpZnjQ== - -"@mui/material@^5.3.0": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.11.9.tgz#fd5b81551f50e4acea2d80feed33728710386f28" - integrity sha512-Wb3WzjzYyi/WKSl/XlF7aC8kk2NE21IoHMF7hNQMkPb0GslbWwR4OUjlBpxtG+RSZn44wMZkEDNB9Hw0TDsd8g== - dependencies: - "@babel/runtime" "^7.20.13" - "@mui/base" "5.0.0-alpha.118" - "@mui/core-downloads-tracker" "^5.11.9" - "@mui/system" "^5.11.9" - "@mui/types" "^7.2.3" - "@mui/utils" "^5.11.9" +"@mui/core-downloads-tracker@^5.12.3": + version "5.12.3" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.12.3.tgz#3dffe62dccc065ddd7338e97d7be4b917004287e" + integrity sha512-yiJZ+knaknPHuRKhRk4L6XiwppwkAahVal3LuYpvBH7GkA2g+D9WLEXOEnNYtVFUggyKf6fWGLGnx0iqzkU5YA== + +"@mui/icons-material@^5.11.16": + version "5.11.16" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.11.16.tgz#417fa773c56672e39d6ccfed9ac55591985f0d38" + integrity sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A== + dependencies: + "@babel/runtime" "^7.21.0" + +"@mui/material@^5.12.3": + version "5.12.3" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.12.3.tgz#398c1b123fb065763558bc1f9fc47d1f8cb87d0c" + integrity sha512-xNmKlrEN4HsTaKFNLZfc7ie7CXx2YqEeO//hsXZx2p3MGtDdeMr2sV3jC4hsFs57RhQlF79weY7uVvC8xSuVbg== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/base" "5.0.0-alpha.128" + "@mui/core-downloads-tracker" "^5.12.3" + "@mui/system" "^5.12.3" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.12.3" "@types/react-transition-group" "^4.4.5" clsx "^1.2.1" - csstype "^3.1.1" + csstype "^3.1.2" prop-types "^15.8.1" react-is "^18.2.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.11.9.tgz#ce3f7b7fa7de3e8d6b2a3132a22bffd6bfaabe9b" - integrity sha512-XMyVIFGomVCmCm92EvYlgq3zrC9K+J6r7IKl/rBJT2/xVYoRY6uM7jeB+Wxh7kXxnW9Dbqsr2yL3cx6wSD1sAg== +"@mui/private-theming@^5.12.3": + version "5.12.3" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.12.3.tgz#f5e4704e25d9d91b906561cae573cda8f3801e10" + integrity sha512-o1e7Z1Bp27n4x2iUHhegV4/Jp6H3T6iBKHJdLivS5GbwsuAE/5l4SnZ+7+K+e5u9TuhwcAKZLkjvqzkDe8zqfA== dependencies: - "@babel/runtime" "^7.20.13" - "@mui/utils" "^5.11.9" + "@babel/runtime" "^7.21.0" + "@mui/utils" "^5.12.3" prop-types "^15.8.1" -"@mui/styled-engine@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.11.9.tgz#105da848163b993522de0deaada82e10ad357194" - integrity sha512-bkh2CjHKOMy98HyOc8wQXEZvhOmDa/bhxMUekFX5IG0/w4f5HJ8R6+K6nakUUYNEgjOWPYzNPrvGB8EcGbhahQ== +"@mui/styled-engine@^5.12.3": + version "5.12.3" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.12.3.tgz#3307643d52c81947a624cdd0437536cc8109c4f0" + integrity sha512-AhZtiRyT8Bjr7fufxE/mLS+QJ3LxwX1kghIcM2B2dvJzSSg9rnIuXDXM959QfUVIM3C8U4x3mgVoPFMQJvc4/g== dependencies: - "@babel/runtime" "^7.20.13" - "@emotion/cache" "^11.10.5" - csstype "^3.1.1" + "@babel/runtime" "^7.21.0" + "@emotion/cache" "^11.10.8" + csstype "^3.1.2" prop-types "^15.8.1" -"@mui/system@^5.11.9": - version "5.11.9" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.11.9.tgz#61f83c538cb4bb9383bcfb39734d9d22ae11c3e7" - integrity sha512-h6uarf+l3FO6l75Nf7yO+qDGrIoa1DM9nAMCUFZQsNCDKOInRzcptnm8M1w/Z3gVetfeeGoIGAYuYKbft6KZZA== +"@mui/styles@^5.12.3": + version "5.12.3" + resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.12.3.tgz#2856fea1002199155bca02d4188b3771539481c6" + integrity sha512-y0GN1kTYO2FF/0LH8a0PpVxwLotlcunFqdJpCL5gza0w5Fqz9wxlwauPZW0bDt0+sF79CrohzdzWkh+fxB+oww== dependencies: - "@babel/runtime" "^7.20.13" - "@mui/private-theming" "^5.11.9" - "@mui/styled-engine" "^5.11.9" - "@mui/types" "^7.2.3" - "@mui/utils" "^5.11.9" + "@babel/runtime" "^7.21.0" + "@emotion/hash" "^0.9.0" + "@mui/private-theming" "^5.12.3" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.12.3" clsx "^1.2.1" - csstype "^3.1.1" + csstype "^3.1.2" + hoist-non-react-statics "^3.3.2" + jss "^10.10.0" + jss-plugin-camel-case "^10.10.0" + jss-plugin-default-unit "^10.10.0" + jss-plugin-global "^10.10.0" + jss-plugin-nested "^10.10.0" + jss-plugin-props-sort "^10.10.0" + jss-plugin-rule-value-function "^10.10.0" + jss-plugin-vendor-prefixer "^10.10.0" prop-types "^15.8.1" -"@mui/types@^7.2.3": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.3.tgz#06faae1c0e2f3a31c86af6f28b3a4a42143670b9" - integrity sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw== +"@mui/system@^5.12.3": + version "5.12.3" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.12.3.tgz#306b3cdffa3046067640219c1e5dd7e3dae38ff9" + integrity sha512-JB/6sypHqeJCqwldWeQ1MKkijH829EcZAKKizxbU2MJdxGG5KSwZvTBa5D9qiJUA1hJFYYupjiuy9ZdJt6rV6w== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/private-theming" "^5.12.3" + "@mui/styled-engine" "^5.12.3" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.12.3" + clsx "^1.2.1" + csstype "^3.1.2" + prop-types "^15.8.1" -"@mui/utils@^5.10.3", "@mui/utils@^5.11.9", "@mui/utils@^5.6.1": +"@mui/types@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" + integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== + +"@mui/utils@^5.10.3": version "5.11.9" resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.11.9.tgz#8fab9cf773c63ad916597921860d2344b5d4b706" integrity sha512-eOJaqzcEs4qEwolcvFAmXGpln+uvouvOS9FUX6Wkrte+4I8rZbjODOBDVNlK+V6/ziTfD4iNKC0G+KfOTApbqg== @@ -1847,15 +2569,27 @@ prop-types "^15.8.1" react-is "^18.2.0" -"@mui/x-data-grid@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@mui/x-data-grid/-/x-data-grid-5.10.0.tgz#22917a8c1a6e95a2d3cde691f53071a838cba0e2" - integrity sha512-+NELUtA+6RAVFHR8sGrSxtJC8+3NQMLflYBm816DXjQvPA8vvCPI50SPKCUYUpBuepQtTBQWcty0Tdm9tjzInA== +"@mui/utils@^5.12.3": + version "5.12.3" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.12.3.tgz#3fa3570dac7ec66bb9cc84ab7c16ab6e1b7200f2" + integrity sha512-D/Z4Ub3MRl7HiUccid7sQYclTr24TqUAQFFlxHQF8FR177BrCTQ0JJZom7EqYjZCdXhwnSkOj2ph685MSKNtIA== dependencies: - "@mui/utils" "^5.6.1" - clsx "^1.1.1" + "@babel/runtime" "^7.21.0" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^16.7.1 || ^17.0.0" + prop-types "^15.8.1" + react-is "^18.2.0" + +"@mui/x-data-grid@5.17.26": + version "5.17.26" + resolved "https://registry.yarnpkg.com/@mui/x-data-grid/-/x-data-grid-5.17.26.tgz#1f7fa73dd3986cf052e2fd2cb56eb4678a7bd913" + integrity sha512-eGJq9J0g9cDGLFfMmugOadZx0mJeOd/yQpHwEa5gUXyONS6qF0OhXSWyDOhDdA3l2TOoQzotMN5dY/T4Wl1KYA== + dependencies: + "@babel/runtime" "^7.18.9" + "@mui/utils" "^5.10.3" + clsx "^1.2.1" prop-types "^15.8.1" - reselect "^4.1.5" + reselect "^4.1.6" "@mui/x-date-pickers@^5.0.17": version "5.0.19" @@ -1891,10 +2625,10 @@ "@babel/runtime" "^7.20.13" "@neo4j-cypher/antlr4-browser" "1.0.0" -"@neo4j-cypher/codemirror@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@neo4j-cypher/codemirror/-/codemirror-1.0.0.tgz#18cace29be6a0fc62eb578de6fb29797480eefb9" - integrity sha512-UozPIig6wIbGWydby3u8CN62TSMFTaFuHtQE50yA614KVBeCk7YXXFTm7rLsgAm10TUC7c48ugDvJNSfXEBCXA== +"@neo4j-cypher/codemirror@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@neo4j-cypher/codemirror/-/codemirror-1.0.2.tgz#34721d5955d31822c9fe170984cd0a85f6b59f91" + integrity sha512-CVRWtw+dGZ1QIrsojCkbjuH6GTwu9wbcWyyawVfjiXmDs6GrmVd4KnTNMRvTdy15Xfc5abdm9rKw8qBxaEFm0w== dependencies: "@babel/runtime" "^7.20.13" "@codemirror/autocomplete" "^6.4.1" @@ -1905,12 +2639,12 @@ "@codemirror/state" "^6.2.0" "@codemirror/view" "^6.9.0" "@lezer/highlight" "^1.1.3" - "@neo4j-cypher/editor-support" "1.0.0" + "@neo4j-cypher/editor-support" "1.0.1" -"@neo4j-cypher/editor-support@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@neo4j-cypher/editor-support/-/editor-support-1.0.0.tgz#c50851ab6c3751c0a46cfcd6996f04704481e557" - integrity sha512-8Poyps1/aluDJI7yTMVybz8KfdZokEFpRz+ACNhAI4/89HIQcqAFtob73iTNni3ACZBoCMB/rxRmaYCEnrv+6g== +"@neo4j-cypher/editor-support@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@neo4j-cypher/editor-support/-/editor-support-1.0.1.tgz#1449a57d36fb72b30766bd096ccb1fa85477a4f4" + integrity sha512-3F4J1YezeNF9zTLdN/bYw+tXgfjGPSvPYHY3GhExTZSoPs4ngPpMpTCUnPDIas5mOs4OF3QlpTrdVjMqk8ryRw== dependencies: "@babel/runtime" "^7.20.13" "@neo4j-cypher/antlr4" "1.0.0" @@ -1918,92 +2652,183 @@ lodash.find "^4.6.0" lodash.includes "^4.3.0" -"@neo4j-cypher/react-codemirror@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@neo4j-cypher/react-codemirror/-/react-codemirror-1.0.0.tgz#6c0242e117de3260c699295de8f938d162df43ef" - integrity sha512-2i92pZoTq6Fuak6HEZEAmqhv0FA/6NocdZnUczOEfmE0jMZuO39LbvNhSJRaESraPuvxIrZHZjIEaeKxFTLd2g== +"@neo4j-cypher/react-codemirror@^1.0.1", "@neo4j-cypher/react-codemirror@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@neo4j-cypher/react-codemirror/-/react-codemirror-1.0.2.tgz#74d2162a20c7a1ac90e8e0898847f362e211559d" + integrity sha512-G+qpzxmjzp/PotSzusD5pbvIlCc1r5BcX6jSI2flNo/kt4HUoKiABydaJPdE7QzJnD+rUVhTs6AfVEcC1GbDBA== dependencies: "@babel/runtime" "^7.20.13" - "@neo4j-cypher/codemirror" "1.0.0" + "@neo4j-cypher/codemirror" "1.0.2" + +"@neo4j-ndl/base@1.7.0", "@neo4j-ndl/base@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-1.7.0.tgz#03b098b06d43efd0debc75a731f34d64683786f4" + integrity sha512-CfAEGeEBpvOGIOXgu7OZaHUofP0Wq4DnnJ7k6z4PgZj9cbSm2AS7PGKyE+fzGzCOqknjL5thYdGnHrVmm5gXlQ== + +"@neo4j-ndl/react@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-1.7.0.tgz#f21d0436f36b3e8ff75dbc03d8215a102b15e997" + integrity sha512-eQK81HPtU6JOpcTP2OnTY9EmjQK1yvnV/0xmYqAygb1dGFQ5CfSx7l0dx462tsnM0kFPBlG9c4qs5KppEAjhzQ== + dependencies: + "@floating-ui/react" "^0.24.2" + "@heroicons/react" "2.0.13" + "@neo4j-cypher/react-codemirror" "^1.0.1" + "@neo4j-ndl/base" "^1.7.0" + "@tanstack/react-table" "^8.5.22" + classnames "^2.3.1" + detect-browser "^5.3.0" + re-resizable "^6.9.9" + react-aria "^3.25.0" + react-dropzone "^14.0.0" + react-focus-lock "^2.9.4" + react-select "5.7.0" + react-syntax-highlighter "^15.5.0" + react-table "^7.7.0" + react-use "^17.4.0" + tinycolor2 "^1.4.2" "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== -"@nivo/annotations@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.80.0.tgz#127e4801fff7370dcfb9acfe1e335781dd65cfd5" - integrity sha512-bC9z0CLjU07LULTMWsqpjovRtHxP7n8oJjqBQBLmHOGB4IfiLbrryBfu9+aEZH3VN2jXHhdpWUz+HxeZzOzsLg== +"@nicolo-ribaudo/semver-v6@^6.3.3": + version "6.3.3" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz#ea6d23ade78a325f7a52750aab1526b02b628c29" + integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg== + +"@nivo/annotations@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.82.1.tgz#93a5d47d02614028fa00570468524e8365145650" + integrity sha512-LmSjO1q9OJS7xmXtpEdJXVngfG0KpucMU/EzKSWK3a7kNmEoe0ri0EHp8MLcYn4VP2end2DYC/RB942Hlh0skQ== + dependencies: + "@nivo/colors" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/prop-types" "^15.7.2" + lodash "^4.17.21" + prop-types "^15.7.2" + +"@nivo/annotations@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/annotations/-/annotations-0.83.0.tgz#d37bfc9d0cfcef53086ef88ff11dc7057bb130e3" + integrity sha512-FkfCprk1a3WCCNcQOfI2+Ww7vqTP/nJjQDVhFYf1YAaEGwXi4+OO4uJAtKtNcGE5cJWdOp+f0Gt4aNPGx7RtEw== dependencies: - "@nivo/colors" "0.80.0" - "@react-spring/web" "9.4.5" + "@nivo/colors" "0.83.0" + "@nivo/core" "0.83.0" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/prop-types" "^15.7.2" lodash "^4.17.21" + prop-types "^15.7.2" -"@nivo/arcs@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/arcs/-/arcs-0.80.0.tgz#87b8308403e245bdc4486cd7f61d2477c5830cd2" - integrity sha512-g5m/wM36Ey45J3hrVDBPMw1Z6GOgIRwgb5zTh7TFoPuhRBZEDQLmctk8XYOm0xOMVCzsm6WkU5wlSQUeBY6IHQ== +"@nivo/arcs@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/arcs/-/arcs-0.82.1.tgz#18223b18d48ba34ecf0ffe42ca1bc91baeafc42a" + integrity sha512-BmcKHW+2Szk6hEfWtnaSKY4GgZWCEmWHPoEX8sXbmisBKLsn0lTROStXEkG2ERa6mP/OB/DNMhTOQnymg7zZKQ== dependencies: - "@nivo/colors" "0.80.0" - "@react-spring/web" "9.4.5" + "@nivo/colors" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" d3-shape "^1.3.5" -"@nivo/axes@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/axes/-/axes-0.80.0.tgz#22788855ddc45bb6a619dcd03d62d4bd8c0fc35f" - integrity sha512-AsUyaSHGwQVSEK8QXpsn8X+poZxvakLMYW7crKY1xTGPNw+SU4SSBohPVumm2jMH3fTSLNxLhAjWo71GBJXfdA== +"@nivo/axes@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/axes/-/axes-0.82.1.tgz#48fac2a60066fbdd6a6b9339c14ec57635210d1b" + integrity sha512-JFWg0gMx4wW1MqzE6/UzI3mCAkl21t/NEVOdVgTN3vsI+9ANXXcHlWumlXuRiOu0xWTAc0AL+dSGWbF5igUnrg== dependencies: - "@nivo/scales" "0.80.0" - "@react-spring/web" "9.4.5" + "@nivo/scales" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-format" "^1.4.1" + "@types/d3-time-format" "^2.3.1" + "@types/prop-types" "^15.7.2" d3-format "^1.4.4" d3-time-format "^3.0.0" + prop-types "^15.7.2" + +"@nivo/axes@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/axes/-/axes-0.83.0.tgz#480026f46b837d710f17e14ebd501286ef8b0b20" + integrity sha512-rHMl+DdXQlY2wl7VCSQNcJi4QNISUWOkcWzJeJeVaYR73Z13SVGgiC7kW0czJuogDTSnDAJ/EcFCGmyGVuznGQ== + dependencies: + "@nivo/core" "0.83.0" + "@nivo/scales" "0.83.0" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-format" "^1.4.1" + "@types/d3-time-format" "^2.3.1" + "@types/prop-types" "^15.7.2" + d3-format "^1.4.4" + d3-time-format "^3.0.0" + prop-types "^15.7.2" -"@nivo/bar@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/bar/-/bar-0.80.0.tgz#6518449aeb068f2ffe263822e44898f3f427d482" - integrity sha512-woE/S12Sp+RKQeOHtp302WXfy5usj73cV/gjP95PzJxMv+Rn01i1Uwys3BILzc9h4+OxYuWTFqLADAySAmi7qQ== - dependencies: - "@nivo/annotations" "0.80.0" - "@nivo/axes" "0.80.0" - "@nivo/colors" "0.80.0" - "@nivo/legends" "0.80.0" - "@nivo/scales" "0.80.0" - "@nivo/tooltip" "0.80.0" - "@react-spring/web" "9.4.5" +"@nivo/bar@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/bar/-/bar-0.82.1.tgz#656f6895fa5739249041cd33a8dc54d20947aa04" + integrity sha512-Qxvr7JOUjp1h90oF1dLZKAIP6CHoq7XVTbq9F68B6PTMqwmHqFEMGyEm9AsyAUm4qMAdg2s3p0L17eXO+kjw6A== + dependencies: + "@nivo/annotations" "0.82.1" + "@nivo/axes" "0.82.1" + "@nivo/colors" "0.82.1" + "@nivo/legends" "0.82.1" + "@nivo/scales" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-scale" "^3.2.3" + "@types/d3-shape" "^2.0.0" d3-scale "^3.2.3" d3-shape "^1.3.5" lodash "^4.17.21" -"@nivo/circle-packing@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/circle-packing/-/circle-packing-0.80.0.tgz#7f6668e9fb6903b42f7bfe5c935acc14a41ee4e6" - integrity sha512-c8IgdzlTk2/oeG3ew8AwcfD8Lz7l5oFMmhlIDp0OUQRrLqFO+GA38ouW2e3IWT2QU33mY4XhDRRdCQgbgFy1zg== +"@nivo/circle-packing@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/circle-packing/-/circle-packing-0.82.1.tgz#51f2f982262f98e4ddb0b682735304a78ffa1a52" + integrity sha512-Yv32pKR/fR48wugZNDIhKmnk+vUGhAbsDmL22QjZ0MF3GHmQ/ivSIgfecaHrG4mtReI0t67uS1FwyA2bX1p8wA== dependencies: - "@nivo/colors" "0.80.0" - "@nivo/tooltip" "0.80.0" - "@react-spring/web" "9.4.5" + "@nivo/colors" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-hierarchy" "^1.1.8" d3-hierarchy "^1.1.8" lodash "^4.17.21" -"@nivo/colors@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/colors/-/colors-0.80.0.tgz#5b70b4979df246d9d0d69fb638bba9764dd88b52" - integrity sha512-T695Zr411FU4RPo7WDINOAn8f79DPP10SFJmDdEqELE+cbzYVTpXqLGZ7JMv88ko7EOf9qxLQgcBqY69rp9tHQ== +"@nivo/colors@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/colors/-/colors-0.82.1.tgz#505013aa088dcf3ae4d6d976a26ebc486cb20557" + integrity sha512-Rcg7zSqFm6lUMig1tIcdY4o9M2IXUi2OEjy7gI1PGHhYEuDBc+OV74GRMegZngH7NoMcnP24aUqe5YpreXABaw== dependencies: - d3-color "^2.0.0" + "@types/d3-color" "^2.0.0" + "@types/d3-scale" "^3.2.3" + "@types/d3-scale-chromatic" "^2.0.0" + "@types/prop-types" "^15.7.2" + d3-color "^3.1.0" d3-scale "^3.2.3" d3-scale-chromatic "^2.0.0" lodash "^4.17.21" + prop-types "^15.7.2" + +"@nivo/colors@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/colors/-/colors-0.83.0.tgz#e8afb2ec10ceb2c0d2b2407f01e11c197c57f78d" + integrity sha512-n34LWYtE2hbd1fdCDP7TCHNZdbiO1PwcvXLo0VsKK5lNPY/FA5SXA7Z9Ubl/ChSwBwbzAsaAhjTy8KzKzSjDcA== + dependencies: + "@nivo/core" "0.83.0" + "@types/d3-color" "^2.0.0" + "@types/d3-scale" "^3.2.3" + "@types/d3-scale-chromatic" "^2.0.0" + "@types/prop-types" "^15.7.2" + d3-color "^3.1.0" + d3-scale "^3.2.3" + d3-scale-chromatic "^2.0.0" + lodash "^4.17.21" + prop-types "^15.7.2" -"@nivo/core@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.80.0.tgz#d180cb2622158eb7bc5f984131ff07984f12297e" - integrity sha512-6caih0RavXdWWSfde+rC2pk17WrX9YQlqK26BrxIdXzv3Ydzlh5SkrC7dR2TEvMGBhunzVeLOfiC2DWT1S8CFg== +"@nivo/core@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.83.0.tgz#d69a7516b5274b6664ca0fa89f1873e749698c1b" + integrity sha512-I9fjZAbIPz41JA2WP8Avsud/xk0iiM1nWUzcvZBDebBGFDB5Y1lrldUt9l5kvOeMth3Qj/1lVFTiJxQuojxH4Q== dependencies: - "@nivo/recompose" "0.80.0" - "@react-spring/web" "9.4.5" - d3-color "^2.0.0" + "@nivo/recompose" "0.83.0" + "@nivo/tooltip" "0.83.0" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-shape" "^2.0.0" + d3-color "^3.1.0" d3-format "^1.4.4" d3-interpolate "^2.0.1" d3-scale "^3.2.3" @@ -2012,125 +2837,238 @@ d3-time-format "^3.0.0" lodash "^4.17.21" -"@nivo/geo@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/geo/-/geo-0.80.0.tgz#ad8e1fdee9bfe7c521cb2bad44d6fce193977c60" - integrity sha512-WKPXaE3K6/4x0hjhGMJqo/vOES3vY/z3R2gmY2h1kghvqpoJZqcygpB3YkU72U1yDD0pTevaQS5XZVUEqVJ/Aw== +"@nivo/core@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/core/-/core-0.82.1.tgz#f997254da276e6c7f494a8646ac67fdae99dc496" + integrity sha512-wcORy9gWHehEpNGidQUNKZsdJwfL06YCYswMSQH37MpdjB5hJyByZwuYSK9+6TDK18IdypVXWehwhp3b9V2LjA== dependencies: - "@nivo/colors" "0.80.0" - "@nivo/legends" "0.80.0" - "@nivo/tooltip" "0.80.0" + "@nivo/recompose" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + d3-color "^3.1.0" + d3-format "^1.4.4" + d3-interpolate "^2.0.1" + d3-scale "^3.2.3" + d3-scale-chromatic "^2.0.0" + d3-shape "^1.3.5" + d3-time-format "^3.0.0" + lodash "^4.17.21" + +"@nivo/geo@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/geo/-/geo-0.82.1.tgz#f15905c3152841cb788449756243c57e9ab50052" + integrity sha512-Xon36UhDhrVIKQ3rgT8B/vlZqwofdO2wtZb9JMkCdyKhBLg6O0h6Z4ETOA0n1RGe7HVhz0Bju5YYm3fw3JmzfA== + dependencies: + "@nivo/colors" "0.82.1" + "@nivo/legends" "0.82.1" + "@nivo/tooltip" "0.82.1" d3-format "^1.4.4" d3-geo "^1.11.3" lodash "^4.17.21" + prop-types "^15.7.2" -"@nivo/legends@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.80.0.tgz#49edc54000075b4df055f86794a8c32810269d06" - integrity sha512-h0IUIPGygpbKIZZZWIxkkxOw4SO0rqPrqDrykjaoQz4CvL4HtLIUS3YRA4akKOVNZfS5agmImjzvIe0s3RvqlQ== - -"@nivo/line@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/line/-/line-0.80.0.tgz#ba541b0fcfd53b3a7ce865feb43c993b7cf4a7d4" - integrity sha512-6UAD/y74qq3DDRnVb+QUPvXYojxMtwXMipGSNvCGk8omv1QZNTaUrbV+eQacvn9yh//a0yZcWipnpq0tGJyJCA== - dependencies: - "@nivo/annotations" "0.80.0" - "@nivo/axes" "0.80.0" - "@nivo/colors" "0.80.0" - "@nivo/legends" "0.80.0" - "@nivo/scales" "0.80.0" - "@nivo/tooltip" "0.80.0" - "@nivo/voronoi" "0.80.0" - "@react-spring/web" "9.4.5" - d3-shape "^1.3.5" +"@nivo/legends@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.82.1.tgz#9bc3f535db0f59264162850ad0c43e01a9b6e46d" + integrity sha512-1PIQMyjyZWzML5rDrUw0FJ7DZinkwm/msb+vH3pF3xq2t2dk863rTe/EDoJlcY8UMjXWftqq+SiAL0hNYdnELw== + dependencies: + "@nivo/colors" "0.82.1" + "@types/d3-scale" "^3.2.3" + "@types/prop-types" "^15.7.2" + d3-scale "^3.2.3" + prop-types "^15.7.2" -"@nivo/pie@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/pie/-/pie-0.80.0.tgz#04b35839bf5a2b661fa4e5b677ae76b3c028471e" - integrity sha512-Zj2PtozUg5wizxdI/2o13YzwnBwf8lLrgc8vH7ucsgOu5nj6oLLpGTuNd3CBmRJHFGIGNT39bP63lKnB3P6qOQ== +"@nivo/legends@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/legends/-/legends-0.83.0.tgz#90f40c9dea6b4f49f07286d0c5429e0ed4eedcec" + integrity sha512-WWl3/hTpFJ7/2L0RG53Gbr9KQk+ZjD71a/RIPMJ5ArEvAvKKfWuWQCtEm3FpqAazX8eYMnsQ3Pi17c8ohEIXRg== dependencies: - "@nivo/arcs" "0.80.0" - "@nivo/colors" "0.80.0" - "@nivo/legends" "0.80.0" - "@nivo/tooltip" "0.80.0" + "@nivo/colors" "0.83.0" + "@nivo/core" "0.83.0" + "@types/d3-scale" "^3.2.3" + "@types/prop-types" "^15.7.2" + d3-scale "^3.2.3" + prop-types "^15.7.2" + +"@nivo/line@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/line/-/line-0.82.1.tgz#5ea97ac73e004fa4bd3df1c6e8435d0d15d79818" + integrity sha512-xG82vlpJC95sBt640JV6LES6UdA7Kdvx64Os9XlM144Idt+30UmlsXr9vr3nVfCKGu5cyl3oa++XebG2KQUTMg== + dependencies: + "@nivo/annotations" "0.82.1" + "@nivo/axes" "0.82.1" + "@nivo/colors" "0.82.1" + "@nivo/legends" "0.82.1" + "@nivo/scales" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@nivo/voronoi" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" d3-shape "^1.3.5" + prop-types "^15.7.2" -"@nivo/radar@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/radar/-/radar-0.80.0.tgz#3dc8d6b41fc6046ad48df5d5fee5af1741d3825d" - integrity sha512-zEXuFb/XlJhaxRoLkoFI4GzKjVO46z+DAfRCNEVr/ijMSEh+56JqN58rDl4TzBGyAEbw2GPzDtchMFMFUsEy6Q== +"@nivo/pie@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/pie/-/pie-0.82.1.tgz#dd69ee36d943dce634bb1203c51df2c21bbd9226" + integrity sha512-ZHlqcwb5iAUm7ga0T/qwMCuK9CaNpSCBcH8VhwVhh+tUgN1U8MbsBGwKrLscTKFOJdSITG54Whl0FgPUz07RWA== dependencies: - "@nivo/colors" "0.80.0" - "@nivo/legends" "0.80.0" - "@nivo/tooltip" "0.80.0" - "@react-spring/web" "9.4.5" + "@nivo/arcs" "0.82.1" + "@nivo/colors" "0.82.1" + "@nivo/legends" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@types/d3-shape" "^2.0.0" + d3-shape "^1.3.5" + +"@nivo/radar@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/radar/-/radar-0.82.1.tgz#a58bee436f247814f71626d77e868c163512beec" + integrity sha512-VmntjNkFxN2VLRM+e7FqEMVKjOIA1mpulG9ZsYS9K8cj/+Ew0G/C5bvinoNxSOeCA7ju+TPXM3t93bhmUqAmpQ== + dependencies: + "@nivo/colors" "0.82.1" + "@nivo/legends" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-scale" "^3.2.3" + "@types/d3-shape" "^2.0.0" d3-scale "^3.2.3" d3-shape "^1.3.5" -"@nivo/recompose@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/recompose/-/recompose-0.80.0.tgz#572048aed793321a0bada1fd176b72df5a25282e" - integrity sha512-iL3g7j3nJGD9+mRDbwNwt/IXDXH6E29mhShY1I7SP91xrfusZV9pSFf4EzyYgruNJk/2iqMuaqn+e+TVFra44A== +"@nivo/recompose@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/recompose/-/recompose-0.82.1.tgz#75adf9fb7148206002d5a9a7cc0a8fdb8ba5e3ff" + integrity sha512-E1wSAF4HjIdgSPnLx4DeQnOz4A+v8pVAEKyTmQr/K9DkhzUy5pxL/Z1UpZ39bNQEj8o73aaXJF7Mp/9nEjaFHA== + dependencies: + "@types/prop-types" "^15.7.2" + "@types/react-lifecycles-compat" "^3.0.1" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.4" + +"@nivo/recompose@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/recompose/-/recompose-0.83.0.tgz#5ea1f638e4a376b0266b8d0761b5ccf27d1db890" + integrity sha512-3cLEoi9ZoE4LTn6B98oUVd0MRAy5bWK7W3yb0u4EkjLoXXCRvUAI08Wr2AAagOzVOg5PmvghIDgvkz1tlFZTGQ== dependencies: + "@types/prop-types" "^15.7.2" + "@types/react-lifecycles-compat" "^3.0.1" + prop-types "^15.7.2" react-lifecycles-compat "^3.0.4" -"@nivo/sankey@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/sankey/-/sankey-0.80.0.tgz#5d0769a4b9ba8139a1590f176f2769c793864c5b" - integrity sha512-jyBHH9FE3klf425x6fXdiCUMPA6Ssf+4ELgu/F0zqz3nd/+u8Bs2hhAiVb6acWnJhu8h/wpI6xDXkrpQpBFAMA== - dependencies: - "@nivo/colors" "0.80.0" - "@nivo/legends" "0.80.0" - "@nivo/tooltip" "0.80.0" - "@react-spring/web" "9.4.5" +"@nivo/sankey@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/sankey/-/sankey-0.82.1.tgz#d484dce26c206a748f7ea4d279c1a51b20c388b0" + integrity sha512-ZEiYH5wJPYJSQXVaS1+jd+esGi+JRtFmcEpMwuL+BG168XhoZg5l7RM+Z0C5jn03dExbqpblrqBT7o5wobuE/g== + dependencies: + "@nivo/colors" "0.82.1" + "@nivo/legends" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-sankey" "^0.11.2" + "@types/d3-shape" "^2.0.0" d3-sankey "^0.12.3" d3-shape "^1.3.5" lodash "^4.17.21" -"@nivo/scales@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/scales/-/scales-0.80.0.tgz#39313fb97c8ae9633c2aa1e17adb57cb851e8a50" - integrity sha512-4y2pQdCg+f3n4TKXC2tYuq71veZM+xPRQbOTgGYJpuBvMc7pQsXF9T5z7ryeIG9hkpXkrlyjecU6XcAG7tLSNg== +"@nivo/scales@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/scales/-/scales-0.82.1.tgz#bb7d446d1ba3ff5197b8c49e286fec663cee0783" + integrity sha512-QV5HMai7lIYnGJz3JnX/PszlI6s+ZD509uoewpZLOZ4oAaT/zPXGWdW2R34+QkPFfTWaH8SCPbLtnzZmeeyCeQ== + dependencies: + "@types/d3-scale" "^3.2.3" + "@types/d3-time" "^1.1.1" + "@types/d3-time-format" "^3.0.0" + d3-scale "^3.2.3" + d3-time "^1.0.11" + d3-time-format "^3.0.0" + lodash "^4.17.21" + +"@nivo/scales@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/scales/-/scales-0.83.0.tgz#82a0ab9df0f3ee487e57ee15ac372d9c6daa21e8" + integrity sha512-DZn5IcMJErCURDuQPmYltu6GTPphTDVLMvbeN/Id/VSVbD1uYKvdXPKUNOe/N2IvnE8wjjCPv88DLcRhw6VTVg== dependencies: + "@types/d3-scale" "^3.2.3" + "@types/d3-time" "^1.1.1" + "@types/d3-time-format" "^3.0.0" d3-scale "^3.2.3" d3-time "^1.0.11" d3-time-format "^3.0.0" lodash "^4.17.21" -"@nivo/sunburst@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/sunburst/-/sunburst-0.80.0.tgz#eb4ca6e44d7a0a4c98571bccec7c405770fb2b8c" - integrity sha512-IMjolRg+nwdPpkoyAcgvAzUfzslAd5FASbCuHWZikjcGLrchlAT1sZNchKwYzUSHKSfvs6RrDC4anj4bh7zZFQ== +"@nivo/scatterplot@^0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/scatterplot/-/scatterplot-0.83.0.tgz#5f665706d160bfb39076b3d4e045d754f2442c04" + integrity sha512-e2T6xNVr97XzP8zqwMv9op2VIzWrkRz7G1n9WbtPF/rTlqY7Um1SeIFQYR0to/87ipZikdcDG2nb9LDpUJp8oQ== + dependencies: + "@nivo/annotations" "0.83.0" + "@nivo/axes" "0.83.0" + "@nivo/colors" "0.83.0" + "@nivo/core" "0.83.0" + "@nivo/legends" "0.83.0" + "@nivo/scales" "0.83.0" + "@nivo/tooltip" "0.83.0" + "@nivo/voronoi" "0.83.0" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-scale" "^3.2.3" + "@types/d3-shape" "^2.0.0" + d3-scale "^3.2.3" + d3-shape "^1.3.5" + lodash "^4.17.21" + +"@nivo/sunburst@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/sunburst/-/sunburst-0.82.1.tgz#1cc2e6a688b328f09cc653a836f6973d68df806e" + integrity sha512-z056uYbWCblYrQyWaLjO20oyf4NGdhZs8KAaVgSWo5kxUIhLdUp3wLS6t/uaAeLjYT9RYiZbzq+R4HexWhoo2g== dependencies: - "@nivo/arcs" "0.80.0" - "@nivo/colors" "0.80.0" - "@nivo/tooltip" "0.80.0" + "@nivo/arcs" "0.82.1" + "@nivo/colors" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@types/d3-hierarchy" "^1.1.8" d3-hierarchy "^1.1.8" lodash "^4.17.21" -"@nivo/tooltip@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/tooltip/-/tooltip-0.80.0.tgz#07ebef47eb708a0612bd6297d5ad156bbec19d34" - integrity sha512-qGmrreRwnCsYjn/LAuwBtxBn/tvG8y+rwgd4gkANLBAoXd3bzJyvmkSe+QJPhUG64bq57ibDK+lO2pC48a3/fw== +"@nivo/tooltip@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/tooltip/-/tooltip-0.82.1.tgz#a3631f660f67c1521556467f19f38e9a212e8ac9" + integrity sha512-5M9YIjxn8DqJ/DcJHWBuPiiLl3p7Zvbt5SRpMF3Rh9FdnuWudtdv+5hrxXmfjoZzRnFl3NphuXi2blhxReZGOQ== + dependencies: + "@react-spring/web" "9.4.5 || ^9.7.2" + +"@nivo/tooltip@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/tooltip/-/tooltip-0.83.0.tgz#aae44c163a6f3bfefcde3491d050cd118af59857" + integrity sha512-HewujRqZNmcVnAv/LPLVyYwViad+rYTsFMdzLRzuTPq2hju1R+cfxokTomunG8e1SDtUPtULEVXtPg2ATIzNYg== dependencies: - "@react-spring/web" "9.4.5" + "@nivo/core" "0.83.0" + "@react-spring/web" "9.4.5 || ^9.7.2" -"@nivo/treemap@^0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/treemap/-/treemap-0.80.0.tgz#cb0ee4e6d87389787ac2d5173dd10948c59f2624" - integrity sha512-0jN0dtZYZTakpqCS4jWPTNkgSy+VUrTFdvM+jHxKYvIa8K7Y6SfxwkCj0+IcIE3czwXczI/ZZ/YJz1dccpXg2w== +"@nivo/treemap@^0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/treemap/-/treemap-0.82.1.tgz#c82b080904ee05aeb5412dd355758c8f90c2b92a" + integrity sha512-OAuEsBs/I3eocfCQPpVKervsy5ZRQFxbwMlqfWbAT0xhQxCKUqBbnyfEFHkaGIVeSs+7YLX7SQm+VaTuMt9a2w== dependencies: - "@nivo/colors" "0.80.0" - "@nivo/tooltip" "0.80.0" - "@react-spring/web" "9.4.5" + "@nivo/colors" "0.82.1" + "@nivo/tooltip" "0.82.1" + "@react-spring/web" "9.4.5 || ^9.7.2" + "@types/d3-hierarchy" "^1.1.8" d3-hierarchy "^1.1.8" lodash "^4.17.21" -"@nivo/voronoi@0.80.0": - version "0.80.0" - resolved "https://registry.yarnpkg.com/@nivo/voronoi/-/voronoi-0.80.0.tgz#59cc7ed253dc1a5bbcf614a5ac37d2468d561599" - integrity sha512-zaJV3I3cRu1gHpsXCIEvp6GGlGY8P7D9CwAVCjYDGrz3W/+GKN0kA7qGyHTC97zVxJtfefxSPlP/GtOdxac+qw== +"@nivo/voronoi@0.82.1": + version "0.82.1" + resolved "https://registry.yarnpkg.com/@nivo/voronoi/-/voronoi-0.82.1.tgz#2e6f2258280a18922548a198a490fc49f8997cd2" + integrity sha512-eANGtiuykU3atwh52evFi/D9l6KdpA2k02/fN3E3hhnKLKP1FuHnTphA4QX25hekuHuOVFX+MDo+VoGyd8bkoA== + dependencies: + "@types/d3-delaunay" "^5.3.0" + "@types/d3-scale" "^3.2.3" + d3-delaunay "^5.3.0" + d3-scale "^3.2.3" + +"@nivo/voronoi@0.83.0": + version "0.83.0" + resolved "https://registry.yarnpkg.com/@nivo/voronoi/-/voronoi-0.83.0.tgz#018c410aa32d032d2caabf762079f227428168bd" + integrity sha512-wVpskesX2IEJHG82v0rbIUZ2y3MpvzTYM+DQl2gx8K1/Hucxwzk5ltg/aF9e/gfKU8gt24uct3M9TQTEfyhzgg== dependencies: + "@nivo/core" "0.83.0" + "@types/d3-delaunay" "^5.3.0" + "@types/d3-scale" "^3.2.3" d3-delaunay "^5.3.0" d3-scale "^3.2.3" @@ -2155,61 +3093,1082 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@popperjs/core@^2.11.6": - version "2.11.6" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" - integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== +"@pmmmwh/react-refresh-webpack-plugin@^0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz#2eba163b8e7dbabb4ce3609ab5e32ab63dda3ef8" + integrity sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA== + dependencies: + ansi-html-community "^0.0.8" + common-path-prefix "^3.0.0" + core-js-pure "^3.23.3" + error-stack-parser "^2.0.6" + find-up "^5.0.0" + html-entities "^2.1.0" + loader-utils "^2.0.4" + schema-utils "^3.0.0" + source-map "^0.7.3" + +"@popperjs/core@^2.11.7": + version "2.11.7" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.7.tgz#ccab5c8f7dc557a52ca3288c10075c9ccd37fff7" + integrity sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw== + +"@react-aria/breadcrumbs@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.2.tgz#2da2d329e7718ec6fa151db8b746c4d69564ad14" + integrity sha512-un10i3vzT7oCftb6jzbMkt6BI/WGlkr+JvWLWFl9CFXH4AlsIU8jWEsrVFUCySSI8Xsj43074zLsnpxgxLgSOA== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/link" "^3.5.1" + "@react-aria/utils" "^3.17.0" + "@react-types/breadcrumbs" "^3.5.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/button@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.7.2.tgz#d2a11766f93242989ad2b90cd948f6da7a086b63" + integrity sha512-flsnMy1xDaTDL+xDzLDeXDAiqNTgbd19R6e4fsDzDPk/mlPgvOSKQtZjswIru4rJR+d29a7LXDemBN/iJEe/3w== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/interactions" "^3.15.1" + "@react-aria/utils" "^3.17.0" + "@react-stately/toggle" "^3.5.2" + "@react-types/button" "^3.7.3" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/calendar@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.3.0.tgz#92a33ad08f5ecc8d22f23af2f87914e711b9b75c" + integrity sha512-K8KATJQjd7xsb9aTe6Cx0/22JrHAiONspSwyGlQlJhHUnpnB6VRvPlVxfEClnbA+oVt04s/vJ87WGVnRNoFI5g== + dependencies: + "@internationalized/date" "^3.2.0" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/live-announcer" "^3.3.0" + "@react-aria/utils" "^3.17.0" + "@react-stately/calendar" "^3.2.1" + "@react-types/button" "^3.7.3" + "@react-types/calendar" "^3.2.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/checkbox@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.9.1.tgz#29e7f1ae66cbafac425099af908f371df4f5f231" + integrity sha512-1TmaqrQ419K6p9KU9v5cGHjStH4p9vOGZsfYYO8RXsQsXmZ7vcK7rjytMeCTdExovU74xK9oXNh64c15Yh9EEA== + dependencies: + "@react-aria/label" "^3.5.2" + "@react-aria/toggle" "^3.6.1" + "@react-aria/utils" "^3.17.0" + "@react-stately/checkbox" "^3.4.2" + "@react-stately/toggle" "^3.5.2" + "@react-types/checkbox" "^3.4.4" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/combobox@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.6.1.tgz#c5f97487eb438092b7f79bfffc51772c264ccc59" + integrity sha512-FdIFAV9appfN5DfoZoJ1D+ZJS3Xp5Kro1oPUPnz9XgthwYV98JinQ5aMBKI4+df0mLmU5z1T3DWbqUuDheUCwg== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/listbox" "^3.9.1" + "@react-aria/live-announcer" "^3.3.0" + "@react-aria/menu" "^3.9.1" + "@react-aria/overlays" "^3.14.1" + "@react-aria/selection" "^3.15.0" + "@react-aria/textfield" "^3.9.2" + "@react-aria/utils" "^3.17.0" + "@react-stately/collections" "^3.8.0" + "@react-stately/combobox" "^3.5.1" + "@react-stately/layout" "^3.12.1" + "@react-types/button" "^3.7.3" + "@react-types/combobox" "^3.6.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/datepicker@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.4.1.tgz#66ebeadaab48cd1f75d9b8495b1d095ceb29327d" + integrity sha512-SRfMwXgLw64WFB7+2uUNjlq4DkOEBNIxuAl5inpk6gef3kK7izSzktbI90uFSA8lcGiN/nIv9G3I2vjz3k1y5Q== + dependencies: + "@internationalized/date" "^3.2.0" + "@internationalized/number" "^3.2.0" + "@internationalized/string" "^3.1.0" + "@react-aria/focus" "^3.12.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/label" "^3.5.2" + "@react-aria/spinbutton" "^3.4.1" + "@react-aria/utils" "^3.17.0" + "@react-stately/datepicker" "^3.4.1" + "@react-types/button" "^3.7.3" + "@react-types/calendar" "^3.2.1" + "@react-types/datepicker" "^3.3.1" + "@react-types/dialog" "^3.5.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/dialog@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.2.tgz#8d2ba539cb98fa99268150dacda1b79365f92fac" + integrity sha512-iKPuk1I9rFHj0y5cjYIoMj4AFeBhWeWWfFDmOuzDx9rsOK6l9jrcAV69LVXtWVJhsmmJs5TP5Ly4OlvpB+9rjA== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/overlays" "^3.14.1" + "@react-aria/utils" "^3.17.0" + "@react-stately/overlays" "^3.5.2" + "@react-types/dialog" "^3.5.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/dnd@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.2.1.tgz#60218ec6fc4e1a8022cf26525ee98157847f3ebe" + integrity sha512-9XvUvBSdaMGD8kwNzbSt+eA0wK465KNrsRJvqYIwUTXhrVjbomzXPm8NQ1e9Y8f7j1vSZU1BlMky0861SHwbWg== + dependencies: + "@internationalized/string" "^3.1.0" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/live-announcer" "^3.3.0" + "@react-aria/overlays" "^3.14.1" + "@react-aria/utils" "^3.17.0" + "@react-aria/visually-hidden" "^3.8.1" + "@react-stately/dnd" "^3.2.1" + "@react-types/button" "^3.7.3" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/focus@^3.12.1": + version "3.12.1" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.12.1.tgz#5976fa41f36d09a0271f736d7c01414704ea1ca2" + integrity sha512-i1bRz27mRFnrDpYpRvm/6Zm+FbGo0WygNQiLVgTce7WY+39oLERIGRrE8Ovy6rY9Hr4MGBAXz2Q+o9oTOgeBgA== + dependencies: + "@react-aria/interactions" "^3.15.1" + "@react-aria/utils" "^3.17.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + clsx "^1.1.1" + +"@react-aria/grid@^3.7.1": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.7.1.tgz#8d68f0bb2c617773c9a640f1a98303542c2dccfc" + integrity sha512-CwrRbX1GuLJnQugB3fkujMPjFEJNyzcy+niuAwRMn768Y9MD8swDMwGrKL362NddF2jSCCwIxqA0qjCPeD4S2w== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/live-announcer" "^3.3.0" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-stately/collections" "^3.8.0" + "@react-stately/grid" "^3.6.1" + "@react-stately/selection" "^3.13.1" + "@react-stately/virtualizer" "^3.5.2" + "@react-types/checkbox" "^3.4.4" + "@react-types/grid" "^3.1.8" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/gridlist@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.4.0.tgz#7273a0e29f610ba8dfa73b4a85a271d7b5aabdfd" + integrity sha512-qV0XIdUrAJMlj+H4d5kL8cH5AFq8m9oNzcDfiA9ku1zsJ9yd3l1waSOyIWlrFZkaIIdkgFUDM4RzgvNHm+WA0Q== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/grid" "^3.7.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-stately/list" "^3.8.1" + "@react-types/checkbox" "^3.4.4" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/i18n@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.7.2.tgz#7e42943a5e0584dca60c72830175edbae4d9be9f" + integrity sha512-GsVioW8RGOmwebTruEBAmGYJunY0WS7Ljfn5n7Mec3eoMKdQjH2M70fHwCOWqJo8Ufq7A7p0ypBVCv4d4sbSdw== + dependencies: + "@internationalized/date" "^3.2.0" + "@internationalized/message" "^3.1.0" + "@internationalized/number" "^3.2.0" + "@internationalized/string" "^3.1.0" + "@react-aria/ssr" "^3.6.0" + "@react-aria/utils" "^3.17.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/interactions@^3.15.1": + version "3.15.1" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.15.1.tgz#10d82fd2ce7a3088713c59cb10b63613c8344052" + integrity sha512-khtpxSvos885rxMep6DRe8RGZjtD16ZuLxhFBtL1dXqSv5XZxaXKOmI8Yx1F8AkVIPdB72MmjG8dz3PpM3PPYg== + dependencies: + "@react-aria/ssr" "^3.6.0" + "@react-aria/utils" "^3.17.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/label@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.5.2.tgz#fa667c04fc19546030e13b49a12dbcd5db323ef1" + integrity sha512-YtLJl3l11TKzGhSMuUqp1DdQ6s3hbT1buiC+jPPKv81PcjjoUDpj+hAVnc1cigtvrEFSMpi2Z+KYREmYYj4GDQ== + dependencies: + "@react-aria/utils" "^3.17.0" + "@react-types/label" "^3.7.4" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/link@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.5.1.tgz#f93914ae5b31b3a38ce1a99809197240113778e3" + integrity sha512-eVdbmiae/Y3B5k78bakx2x43c69cqvEk/g38kjRI4lNa1WsQMdV/3HXjuWa3KA+c3ajn0kTAXO6inHKGtJ9d6w== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/interactions" "^3.15.1" + "@react-aria/utils" "^3.17.0" + "@react-types/link" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/listbox@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.9.1.tgz#8b077a02fc9a6179c7660d0f3aca83bbf43eb714" + integrity sha512-tRcqNHGx9Vtspth9zdOLEfbGGaLrTN/rDXg0xN2FT++qxwALuYV7R4qFUX7eTPCT+NDOqeQNOCsHyQF4gQN+JQ== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/interactions" "^3.15.1" + "@react-aria/label" "^3.5.2" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-stately/collections" "^3.8.0" + "@react-stately/list" "^3.8.1" + "@react-types/listbox" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/live-announcer@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.3.0.tgz#04a2a233c2f48c53994f83cafdc4336ec1ea3700" + integrity sha512-6diTS6mIf70KdxfGqiDxHV+9Qv8a9A88EqBllzXGF6HWPdcwde/GIEmfpTwj8g1ImNGZYUwDkv4Hd9lFj0MXEg== + dependencies: + "@swc/helpers" "^0.4.14" + +"@react-aria/menu@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.9.1.tgz#a89f8c65429c50d5247a46fd100454ec3efb37e5" + integrity sha512-LRSo7KyVxoFxrjj55VtxMKJ6/c3LhfZThytWFvA9r02Ukf1B0xn/Or8rgyVyHcyekvcmT4IDrjFl1tDG2wsq4g== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/overlays" "^3.14.1" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-stately/collections" "^3.8.0" + "@react-stately/menu" "^3.5.2" + "@react-stately/tree" "^3.6.1" + "@react-types/button" "^3.7.3" + "@react-types/menu" "^3.9.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/meter@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.2.tgz#741bf22176a349c0973d9480c9c306ebb5d81545" + integrity sha512-3qcWeCiLuauwQdLHOc/RssuxEEhYWEy+TXNNE2P6zKvduuL19JKKljpuI1SpQSQ4nAamIGZwGBwHdAoZpLx3Kw== + dependencies: + "@react-aria/progress" "^3.4.2" + "@react-types/meter" "^3.3.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/numberfield@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.5.1.tgz#e4f97e24dd755e2092a8afa2689a82798e610105" + integrity sha512-O0hDANrlwsKSKjiV64Ryx1FfNxkuByU9qXKz7vpMf8ZeR3OLAYzvib1RNeFvijM9/TUGp1zA40cwGknEp6D72w== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/live-announcer" "^3.3.0" + "@react-aria/spinbutton" "^3.4.1" + "@react-aria/textfield" "^3.9.2" + "@react-aria/utils" "^3.17.0" + "@react-stately/numberfield" "^3.4.2" + "@react-types/button" "^3.7.3" + "@react-types/numberfield" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@react-types/textfield" "^3.7.2" + "@swc/helpers" "^0.4.14" + +"@react-aria/overlays@^3.14.1": + version "3.14.1" + resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.14.1.tgz#2e18bd78eef145dc1353490dbe29f04622cfbafe" + integrity sha512-xJCw0oSDtwBCCqf0EMMeeLYOEFSCdd1cWFS0O3980SObFQPHwP5KOX5SAs7lVvIlZUvEdpo6sOytcQTjv5U9QA== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/ssr" "^3.6.0" + "@react-aria/utils" "^3.17.0" + "@react-aria/visually-hidden" "^3.8.1" + "@react-stately/overlays" "^3.5.2" + "@react-types/button" "^3.7.3" + "@react-types/overlays" "^3.7.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/progress@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.2.tgz#a4357c718808cacf01e83e162d2e3968dc623629" + integrity sha512-9VQbZGWnzQz8pW7NoOzUNzVkWemTaCfut8KJHcyW/KicoNfNHNuhaBcFvor0pAGIYT4Kdxlv0aG6i3N1xit6aQ== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/label" "^3.5.2" + "@react-aria/utils" "^3.17.0" + "@react-types/progress" "^3.4.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/radio@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.6.1.tgz#baf5d83b99b5ef44fa0bed804daa2fb221ecf754" + integrity sha512-paO2sCxvH8I0Iomzgmvw1TCvzd+0AcUylPSr34dhPmJIsRew7UVtmON9YU8tM/KELDv346n2v8KqzlgHJlLLvg== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/label" "^3.5.2" + "@react-aria/utils" "^3.17.0" + "@react-stately/radio" "^3.8.1" + "@react-types/radio" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/searchfield@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.5.2.tgz#9ff0031130c73be1007822f9b99a6ef9967a5930" + integrity sha512-rmTdr1ZYqVOZ9lTf2ks71ohirgNsutuG8If6r2FFvatc8UgOG/ClKeaTHhErPKLtO9+SxQWDGmi72ShF92Ydjw== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/textfield" "^3.9.2" + "@react-aria/utils" "^3.17.0" + "@react-stately/searchfield" "^3.4.2" + "@react-types/button" "^3.7.3" + "@react-types/searchfield" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/select@^3.10.1": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.10.1.tgz#eb6be7dd29f40ced0c1c4aaedf698ca43790b0bd" + integrity sha512-gu+ssmcT7kA9B9PCFaY/LyWPtNk0Ywl51qFM4S8JVTM3sMqnUPVjFHFp/UYL6NK1pZa9Saui4c4HZCGc+HcQlQ== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/label" "^3.5.2" + "@react-aria/listbox" "^3.9.1" + "@react-aria/menu" "^3.9.1" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-aria/visually-hidden" "^3.8.1" + "@react-stately/select" "^3.5.1" + "@react-types/button" "^3.7.3" + "@react-types/select" "^3.8.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/selection@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.15.0.tgz#928acf8adffea1afe64a152b6fe425a5424e52f5" + integrity sha512-v3AXsau6BobbM5Fu7X+HhX5K/Ey3drVBaoevGDiYX8kGS9jlFNDXENKYPtnMpcTCvSX0yuxTITukOEBokzkb6Q== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/utils" "^3.17.0" + "@react-stately/collections" "^3.8.0" + "@react-stately/selection" "^3.13.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/separator@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.3.2.tgz#38a895a06ad61b4d3304c173c36f357bf6b3ed89" + integrity sha512-JNftOexcj8lvKRS7h+gTIW4HBJVtcYRc8ESCt7GFgAozVNmu+IJ6KPvD1MYBozCLzoKGnLPXB/9eGi47wNdXnA== + dependencies: + "@react-aria/utils" "^3.17.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/slider@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.4.1.tgz#b56c4b1bb82a4038150c2e67953a55e3337e6231" + integrity sha512-gJTfwZGGGv0dPUO3rC8HCyOXnAgMagJZnV3gIILfzNWZHZLYbLze+IbTSNtNKGIvt4pAKTV0njLDLlxFZlAadw== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/label" "^3.5.2" + "@react-aria/utils" "^3.17.0" + "@react-stately/radio" "^3.8.1" + "@react-stately/slider" "^3.3.2" + "@react-types/radio" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@react-types/slider" "^3.5.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/spinbutton@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.4.1.tgz#627db560317fee187854d48c6e31a4f2f0591a3e" + integrity sha512-YL3Gp431Jd8FcZ3aU/ymQJlV1yPOShbDJUvHZ8cwasjFH3QLSvx88pcv1PTKxyE3RdRFkP+Xii61jFfF7B5jmg== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/live-announcer" "^3.3.0" + "@react-aria/utils" "^3.17.0" + "@react-types/button" "^3.7.3" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/ssr@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.6.0.tgz#e5d52bd1686ff229f68f806cf94ee29dd9f54fb7" + integrity sha512-OFiYQdv+Yk7AO7IsQu/fAEPijbeTwrrEYvdNoJ3sblBBedD5j5fBTNWrUPNVlwC4XWWnWTCMaRIVsJujsFiWXg== + dependencies: + "@swc/helpers" "^0.4.14" + +"@react-aria/switch@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.5.1.tgz#e85e90ca735462c3aa4e1c5ed5b877332195d2f8" + integrity sha512-upFtDIfNSVUOUOQYPqFzu2dxef4zVcxbCkaqUo+IRJnNix6AdtoEq+E7gwKVHnB79GQMWz6ZmippbID9Yrq73Q== + dependencies: + "@react-aria/toggle" "^3.6.1" + "@react-stately/toggle" "^3.5.2" + "@react-types/switch" "^3.3.2" + "@swc/helpers" "^0.4.14" + +"@react-aria/table@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.9.1.tgz#e30b9703c9dc4f6d7e0b3d2851a5092625db2f19" + integrity sha512-utcqmQbH9M6jw6Stv8ugJdi8+F0vCXE7pQMVDow/mxDq0Cf5bAbBt29Yln2xO/6dyiBcT3LESgmD7AYlAfy2BQ== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/grid" "^3.7.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/live-announcer" "^3.3.0" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-aria/visually-hidden" "^3.8.1" + "@react-stately/collections" "^3.8.0" + "@react-stately/table" "^3.9.1" + "@react-stately/virtualizer" "^3.5.2" + "@react-types/checkbox" "^3.4.4" + "@react-types/grid" "^3.1.8" + "@react-types/shared" "^3.18.1" + "@react-types/table" "^3.6.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/tabs@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.6.0.tgz#18bd02557acb3212cf34134a1343cacaad075a02" + integrity sha512-W+X/lEvGjIGOeIx/tzkXjenglRPdv6d0JS4KCqrQET+Vg4jkAJWR2Ls0imz6CIF/QE5lbe3MiM8pyFpwg6vUNA== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-stately/list" "^3.8.1" + "@react-stately/tabs" "^3.4.1" + "@react-types/shared" "^3.18.1" + "@react-types/tabs" "^3.3.0" + "@swc/helpers" "^0.4.14" + +"@react-aria/tag@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.0.0.tgz#6bc61544d396a97bfcf77d1186d7821268d81aa1" + integrity sha512-UuYqlysitwv1e1SV9YJqUMV7P7Gg5triEljyJ90b4rtETRhGa+Qh6cVa1P8F4h5nPTwzqey47jAp45i1FSsH4w== + dependencies: + "@react-aria/gridlist" "^3.4.0" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/label" "^3.5.2" + "@react-aria/selection" "^3.15.0" + "@react-aria/utils" "^3.17.0" + "@react-stately/list" "^3.8.1" + "@react-types/button" "^3.7.3" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/textfield@^3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.9.2.tgz#d73c29906e38a988a193122ec2e17b1108366502" + integrity sha512-wT68tErfMcBvJHyb+5skfs1OHZ8lESzIbrwCTuipM85BeleYIu25qGbKfOX9wMbC+4X775gg/JfmUQESJ6nD1A== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/label" "^3.5.2" + "@react-aria/utils" "^3.17.0" + "@react-types/shared" "^3.18.1" + "@react-types/textfield" "^3.7.2" + "@swc/helpers" "^0.4.14" + +"@react-aria/toggle@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.6.1.tgz#9aa8c6b951ef4c9a407e410da0079e046d8b35f1" + integrity sha512-4ml3HMjaZPUtRVb6MuuxuV8P/ydzrpldfP0R1hv3f56lo5gBVMh7ME72z49Z8Jf9hnxPkDBvnNi0AnfITtvfVw== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/interactions" "^3.15.1" + "@react-aria/utils" "^3.17.0" + "@react-stately/toggle" "^3.5.2" + "@react-types/checkbox" "^3.4.4" + "@react-types/shared" "^3.18.1" + "@react-types/switch" "^3.3.2" + "@swc/helpers" "^0.4.14" + +"@react-aria/tooltip@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.5.1.tgz#fd6f157cc6f09986e986e38034ad5198e3514dc0" + integrity sha512-H+eYX5H9cSKCiguH/0+QMq9LrZrvq8D0Zf6fHnA3dP4YkDjxFNuFyeiXGSTTcjEmwnCf9sJ9sObjv6b9n7c45w== + dependencies: + "@react-aria/focus" "^3.12.1" + "@react-aria/interactions" "^3.15.1" + "@react-aria/utils" "^3.17.0" + "@react-stately/tooltip" "^3.4.1" + "@react-types/shared" "^3.18.1" + "@react-types/tooltip" "^3.4.1" + "@swc/helpers" "^0.4.14" + +"@react-aria/utils@^3.17.0": + version "3.17.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.17.0.tgz#b462afad9a25505394a714a69b9f238c24dd15a7" + integrity sha512-NEul0cQ6tQPdNSHYzNYD+EfFabeYNvDwEiHB82kK/Tsfhfm84SM+baben/at2N51K7iRrJPr5hC5fi4+P88lNg== + dependencies: + "@react-aria/ssr" "^3.6.0" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + clsx "^1.1.1" + +"@react-aria/visually-hidden@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.1.tgz#f035d3461671ae6f3af534e615df009ca9c08c4a" + integrity sha512-aojoZXw5iaFDOgqmGuCyaTG9PFqfav5ABXX/W/0Q2YNj6Tb3i6++m2+8RMHlz2b6Dj+rXLiTxa00t7BSgJbUvA== + dependencies: + "@react-aria/interactions" "^3.15.1" + "@react-aria/utils" "^3.17.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + clsx "^1.1.1" "@react-leaflet/core@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@react-leaflet/core/-/core-1.1.1.tgz#827fd05bb542cf874116176d8ef48d5b12163f81" integrity sha512-7PGLWa9MZ5x/cWy8EH2VzI4T8q5WpuHbixzCDXqixP/WyqwIrg5NDUPgYuFnB4IEIZF+6nA265mYzswFo/h1Pw== -"@react-spring/animated@~9.4.5": - version "9.4.5" - resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.4.5.tgz#dd9921c716a4f4a3ed29491e0c0c9f8ca0eb1a54" - integrity sha512-KWqrtvJSMx6Fj9nMJkhTwM9r6LIriExDRV6YHZV9HKQsaolUFppgkOXpC+rsL1JEtEvKv6EkLLmSqHTnuYjiIA== +"@react-spring/animated@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.7.2.tgz#0119db8075e91d693ec45c42575541e01b104a70" + integrity sha512-ipvleJ99ipqlnHkz5qhSsgf/ny5aW0ZG8Q+/2Oj9cI7LCc7COdnrSO6V/v8MAX3JOoQNzfz6dye2s5Pt5jGaIA== + dependencies: + "@react-spring/shared" "~9.7.2" + "@react-spring/types" "~9.7.2" + +"@react-spring/core@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.7.2.tgz#804ebadee45a6adff00886454d6f1c5d97ee219d" + integrity sha512-fF512edZT/gKVCA90ZRxfw1DmELeVwiL4OC2J6bMUlNr707C0h4QRoec6DjzG27uLX2MvS1CEatf9KRjwZR9/w== + dependencies: + "@react-spring/animated" "~9.7.2" + "@react-spring/rafz" "~9.7.2" + "@react-spring/shared" "~9.7.2" + "@react-spring/types" "~9.7.2" + +"@react-spring/rafz@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.7.2.tgz#77e7088c215e05cf893851cd87ceb40d89f2a7d7" + integrity sha512-kDWMYDQto3+flkrX3vy6DU/l9pxQ4TVW91DglQEc11iDc7shF4+WVDRJvOVLX+xoMP7zyag1dMvlIgvQ+dvA/A== + +"@react-spring/shared@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.7.2.tgz#b8485617bdcc9f6348b245922051fb534e07c566" + integrity sha512-6U9qkno+9DxlH5nSltnPs+kU6tYKf0bPLURX2te13aGel8YqgcpFYp5Av8DcN2x3sukinAsmzHUS/FRsdZMMBA== + dependencies: + "@react-spring/rafz" "~9.7.2" + "@react-spring/types" "~9.7.2" + +"@react-spring/types@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.7.2.tgz#e04dd72755d88b0e3163ba143ecd8ba78b68a5b0" + integrity sha512-GEflx2Ex/TKVMHq5g5MxQDNNPNhqg+4Db9m7+vGTm8ttZiyga7YQUF24shgRNebKIjahqCuei16SZga8h1pe4g== + +"@react-spring/web@9.4.5 || ^9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.7.2.tgz#76e53dd24033764c3062f9927f88b0f3194688d4" + integrity sha512-7qNc7/5KShu2D05x7o2Ols2nUE7mCKfKLaY2Ix70xPMfTle1sZisoQMBFgV9w/fSLZlHZHV9P0uWJqEXQnbV4Q== + dependencies: + "@react-spring/animated" "~9.7.2" + "@react-spring/core" "~9.7.2" + "@react-spring/shared" "~9.7.2" + "@react-spring/types" "~9.7.2" + +"@react-stately/calendar@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.2.1.tgz#834b1bb5b0412dcbfc9cd1edea3cd19c99a62286" + integrity sha512-3gUUQofRfMaFqg8qA0uEMuciDAtFCYhxYgYWwWOIBcpxHV0STMKrsWjpY5+rNtpB+wi+81jz55gfmBEo+4QU3w== + dependencies: + "@internationalized/date" "^3.2.0" + "@react-stately/utils" "^3.6.0" + "@react-types/calendar" "^3.2.1" + "@react-types/datepicker" "^3.3.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/checkbox@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.4.2.tgz#9ccd80ee94b5d4c796e81ce8f5e55230b8102e31" + integrity sha512-UG94lilDJEIFeRKnKw31nI1Vb1UOSroLAFHv4rB2tCvzLl3/9ULfHyii1hqFVS41juzFc7ONInNBT4yu5RAm5Q== + dependencies: + "@react-stately/toggle" "^3.5.2" + "@react-stately/utils" "^3.6.0" + "@react-types/checkbox" "^3.4.4" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/collections@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.8.0.tgz#4b2b71866d12fd6b4f4aea495e2d4ecb2954d4e6" + integrity sha512-NIRE8Gha0XZTnbvh9JRZM7oI/6uLf6ozjB7myja29IX7hDvsZxITe0RFXBapcujlpXLU2uufssJPKpiwJm3vZQ== + dependencies: + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/combobox@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.5.1.tgz#efde39fa2d5003d9030bef04705aefc84f00aff7" + integrity sha512-E7eEggbVaueLEeSAOXzB2wUsjxgA3vpfTsghWdxYU6hWPB2ek6cSWfjAp7NPtf0b56n07kZRqa1lFx6kPJSCYw== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/list" "^3.8.1" + "@react-stately/menu" "^3.5.2" + "@react-stately/select" "^3.5.1" + "@react-stately/utils" "^3.6.0" + "@react-types/combobox" "^3.6.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/datepicker@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.4.1.tgz#3aaf3b439e542aa9bc0dc366a70f9232247865e6" + integrity sha512-tubL36Pc7H3/agUk3epB9YzVDUgCNhE406cAMpkvFP4Ru4pUC45dKM9FoR4S43vJra7AYfY8lNkFZKkFVJBWVQ== + dependencies: + "@internationalized/date" "^3.2.0" + "@internationalized/string" "^3.1.0" + "@react-stately/overlays" "^3.5.2" + "@react-stately/utils" "^3.6.0" + "@react-types/datepicker" "^3.3.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/dnd@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.2.1.tgz#3f738d4a1bbc9c2291c52ec480114b96e83ed76a" + integrity sha512-n9XHGUOvDiSWiNJ/MtgvGz/nY3OX9rMJi1pjx6066m699qu1qYDQUgBI59HLCHBf1DhrYWz2qDf72rkxdbgZ6g== + dependencies: + "@react-stately/selection" "^3.13.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/grid@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.6.1.tgz#968fde7289ec97e40171586b53cfc69e70d00718" + integrity sha512-54B3OztU99ixMhcZsDdfeMemEcqibK9KgaOZVuPmewee35nXAOGTqNjjeN64Vz6ui8q3j86eIyjGChAxqU0KpA== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/selection" "^3.13.1" + "@react-types/grid" "^3.1.8" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/layout@^3.12.1": + version "3.12.1" + resolved "https://registry.yarnpkg.com/@react-stately/layout/-/layout-3.12.1.tgz#ec4602fe723cab9652ce206aa6e6490b6f24c9b5" + integrity sha512-WVAo9bb8+QWOkGC0HUkYOGjkXvUuZyOOtftc0blRnuGD30SAx1bLkGEFoa2Qm6K7Rhm7s9jNSSXdd6Tgm4Aqew== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/table" "^3.9.1" + "@react-stately/virtualizer" "^3.5.2" + "@react-types/grid" "^3.1.8" + "@react-types/shared" "^3.18.1" + "@react-types/table" "^3.6.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/list@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.8.1.tgz#19ed21dc2929e6a5a1e05a1858dbc7ee1f55f761" + integrity sha512-QO2hKRnXaz2L1v/KYPmDKeD+PfEScp4KiJMFzU/T9vvjxIratSTg314B25Xj4LJq+JhyxlguylxBF9r/R6qUjQ== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/selection" "^3.13.1" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/menu@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.5.2.tgz#c6201d2f928f4bf548b743b06f855dd8bef04daa" + integrity sha512-BgGK3NleNGcByadG990ccdwr4oQiAN6meGf0gbIwrisikNdnL1XxgzCj+RMEooBtV+qakR+3KtVAnc97E5WiOQ== + dependencies: + "@react-stately/overlays" "^3.5.2" + "@react-stately/utils" "^3.6.0" + "@react-types/menu" "^3.9.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/numberfield@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.4.2.tgz#05a2b94850cf3a1e703c6323068a11cdb15bf5ae" + integrity sha512-FFe8J38//+Ck3aSTCtWteQY6tkDi2curLPxFwkWOxq71Vv+1Zvga5pTRoa6O1k1f0OXnDkVhmU1Njcl4JRMveA== + dependencies: + "@internationalized/number" "^3.2.0" + "@react-stately/utils" "^3.6.0" + "@react-types/numberfield" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/overlays@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.5.2.tgz#b084789fa2e3bcf30348fe09e848acccf01957c9" + integrity sha512-NEwkF/ukXzI/Ku+6j6MhhqdMc5xMgDnuR6RwFPsoPq6UoHw9/ojifxg/sDj5e1gPoegNZ2nM8G6VmnPUGabg/g== + dependencies: + "@react-stately/utils" "^3.6.0" + "@react-types/overlays" "^3.7.2" + "@swc/helpers" "^0.4.14" + +"@react-stately/radio@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.8.1.tgz#9594044754894cd6edfdb99db8d5fc26b7e9d32c" + integrity sha512-yhz6/2y/hkDW7dzjhNsxrVZ8T7n2/Y9LyVRKDCL7ZYOkpoVQGe0ELbU04ATJPHNx6Icg/jAfN0Z/uMov/q4VBQ== + dependencies: + "@react-stately/utils" "^3.6.0" + "@react-types/radio" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/searchfield@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.4.2.tgz#fd9b87504dc0c394eb4be5e5d59b2b3ecdd10e2f" + integrity sha512-MGxjDY3lV4q3eFRiFbDhzicXWFdcAQ84klbFeWnSg/QLebQPyWD9X35e3Gc8bkNKof2MmwcrEgUIuHOReDRr2w== + dependencies: + "@react-stately/utils" "^3.6.0" + "@react-types/searchfield" "^3.4.2" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/select@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.5.1.tgz#15b00012f20804e640b80fe3d275ab3ceb75ac02" + integrity sha512-a6/Y3yRwinYR08Pq7Vj2HjOLtRgn5Ctmorx+UR7hBekvV/7scu9RqNI3i/yxyF+8y7KeymuwuMe1iohn4uAP+g== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/list" "^3.8.1" + "@react-stately/menu" "^3.5.2" + "@react-stately/selection" "^3.13.1" + "@react-stately/utils" "^3.6.0" + "@react-types/select" "^3.8.1" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/selection@^3.13.1": + version "3.13.1" + resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.13.1.tgz#17752ed81bf0f3246cd010818c460fa0d749d3a1" + integrity sha512-0B+gT6hyei/pzUSmrNliphoztOPZJ7v/xVT9b4HViRTwuOUQlmwi5BQai84EbVtgQaQghc07sJ/Y/Ec8WXCRHA== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/slider@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.3.2.tgz#9e933fe5078ed0272f398c1c11ad078b7945b53d" + integrity sha512-UHyBdFR/3Wl1UZmwxWwJ1rb/OCYhY62zZaN7GZrVsnjQ0ng7mFqkb6O0/SXWjsfXnmRAMqCg4ARk82d1PRUfsg== + dependencies: + "@react-aria/i18n" "^3.7.2" + "@react-aria/utils" "^3.17.0" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.18.1" + "@react-types/slider" "^3.5.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/table@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.9.1.tgz#628d5099e76cf9e81926b752ec178376dec7bda1" + integrity sha512-/YWpV88RH4ElCiwNm/Ys+A5nyWhy+BwEsGTVatbjwZFmHwHxv1FeMrTiYZ9vXR7V7SMCvA8Pd9OJ9NmRkd2klg== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/grid" "^3.6.1" + "@react-stately/selection" "^3.13.1" + "@react-types/grid" "^3.1.8" + "@react-types/shared" "^3.18.1" + "@react-types/table" "^3.6.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/tabs@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.4.1.tgz#f1d74551808f4d0a33f1c8d0e918bfbb5feeea03" + integrity sha512-8MTerdCSaZEc0qghINqIe/L/ja1Lbo5v5aFwJS014VjhYc2uFyJlTn+/kyccClBlmXpARqmiC7C3ASJ33385Fg== + dependencies: + "@react-stately/list" "^3.8.1" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.18.1" + "@react-types/tabs" "^3.3.0" + "@swc/helpers" "^0.4.14" + +"@react-stately/toggle@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.5.2.tgz#580f4254e3c7c2c4d230409a36042813d9c0ab70" + integrity sha512-2fDecu06job9NKdSIryU4AE+BoTGZqfinUsAvYTaaQN95Apq8IShEDFkY+gSnU09wRX26Ux+JJi5pYwg+HX1tw== + dependencies: + "@react-stately/utils" "^3.6.0" + "@react-types/checkbox" "^3.4.4" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/tooltip@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.4.1.tgz#cee27bfcabfa54e37e7627f71ac2e3eb2da8495d" + integrity sha512-ZHqyN/mqciKtUfQ/bwdPPPAKwVFeFfyMLkHSA34NrXr9/swj/ONBQtdRUzbu56rlajMUSw5R60hmyJOGNXZb3A== + dependencies: + "@react-stately/overlays" "^3.5.2" + "@react-stately/utils" "^3.6.0" + "@react-types/tooltip" "^3.4.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/tree@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.6.1.tgz#191daac8dfd52a3603e2e138cab26fd2bfd493c3" + integrity sha512-KfaUoc0/PeT9W25e/7jG1VGeTO54KDKULveuUqLFJEJeP8M8vCgT5Og4YdJkPfu//dlL8OZu1y6ZpdyA9+LBsg== + dependencies: + "@react-stately/collections" "^3.8.0" + "@react-stately/selection" "^3.13.1" + "@react-stately/utils" "^3.6.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-stately/utils@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.6.0.tgz#f273e7fcb348254347d2e88c8f0c45571060c207" + integrity sha512-rptF7iUWDrquaYvBAS4QQhOBQyLBncDeHF03WnHXAxnuPJXNcr9cXJtjJPGCs036ZB8Q2hc9BGG5wNyMkF5v+Q== + dependencies: + "@swc/helpers" "^0.4.14" + +"@react-stately/virtualizer@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-stately/virtualizer/-/virtualizer-3.5.2.tgz#f646a114662c18d34afbf3b1cba81636afadb231" + integrity sha512-OmG9lPcbfnyuPhbSDVcDXDfPU0rc2E/V8VLGGd/yMOxSy4S90nWDSEoR8qAN6g9rY6xoLjPJ671nyxOu41EtyA== + dependencies: + "@react-aria/utils" "^3.17.0" + "@react-types/shared" "^3.18.1" + "@swc/helpers" "^0.4.14" + +"@react-types/breadcrumbs@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.5.2.tgz#1717f3ffbad2d5da457195cb50c9d9c0a5b6be8f" + integrity sha512-pKtahBLmcpSYhfNBv2j/k0e701U7xwDCf24U/JOyio9i7aAYCZ+RUcKc1kK3tRsVNj41seLv7Q9ElC48nXsfwg== + dependencies: + "@react-types/link" "^3.4.2" + "@react-types/shared" "^3.18.1" + +"@react-types/button@^3.7.3": + version "3.7.3" + resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.7.3.tgz#00ad45ff0a304a6f6ef29a5d6adda73cea10942f" + integrity sha512-Fz1t/kYinHDunmct3tADD2h3UDBPZUfRE+zCzYiymz0g+v/zYHTAqnkWToTF9ptf8HIB5L2Z2VFYpeUHFfpWzg== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/calendar@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.2.1.tgz#f01bff7c373b19a18d96414b0680903ca508ae85" + integrity sha512-lp+1KG7YxKCPvXuuyB1XyyhynV8g19JamojfGUaQGqsM1kxOr8x87Ikwh5zunHuOS6U4s/tO0C2LMA9iGxdBxQ== + dependencies: + "@internationalized/date" "^3.2.0" + "@react-types/shared" "^3.18.1" + +"@react-types/checkbox@^3.4.4": + version "3.4.4" + resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.4.4.tgz#cf55e9fd0cabef6e4408d03b308c754e1add3bc1" + integrity sha512-rJNhbW4R9HTvdbF2oTZmqGiZ/WVP3/XsU4gae7tfdhSYjG+5T5h9zau1vRhz++zwKn57wfcyNn6a83GDhhgkVw== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/combobox@^3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.6.2.tgz#887cc2bce355773cb9dc5613c88264d008c92384" + integrity sha512-qitu/W3Z3/ihyqocy+8n4HZKRXF5JTMHl1ug3rKps5yCNnVdkWwjPFPM6w180c9QjquThNY3o947LZ1v59qJ4A== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/datepicker@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.3.1.tgz#035451586577077a65b89ee739bd1e29a777a28b" + integrity sha512-kVZ9j3PovXjTIeQrq4YiURS48Rsp5Uc81/HumZyrTWtYtYSKAU0U0ifiTuPeJ044tfpi3wGkitJ5wtt8j5imKQ== + dependencies: + "@internationalized/date" "^3.2.0" + "@react-types/overlays" "^3.7.2" + "@react-types/shared" "^3.18.1" + +"@react-types/dialog@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.2.tgz#e0dd2b459ebfeae649a93cd69f4fd12b8b043c71" + integrity sha512-eus/TivlVqA8JNunMGv9w0Ey4Fmao6BRA3/2r6WTcbXTRw+nLXMmNO2j4CzXAhtrT5j187SADP5OXZjWuEzLFw== + dependencies: + "@react-types/overlays" "^3.7.2" + "@react-types/shared" "^3.18.1" + +"@react-types/grid@^3.1.8": + version "3.1.8" + resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.1.8.tgz#2d8cf3ccbb2bba161917b9e242f920fed5f34026" + integrity sha512-NKk4pDbW2QXJOYnDSAYhta81CGwXOc/9tVw2WFs+1wacvxeKmh1Q+n36uAFcIdQOvVRqeGTJaYiqLFmF3fC3tA== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/label@^3.7.4": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@react-types/label/-/label-3.7.4.tgz#db7ce5cc82785b11ed4c80308b2ec40768fec6e0" + integrity sha512-SfTqPRI39GE3GFD5ZGYEeX9jXQrNqDeaaI36PJhnbgGVFz96oVVkhy9t9c2bMHcbhLLENYIHMzxrvVqXS07e7A== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/link@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.4.2.tgz#85fd550284bf1270dcbdc7c31965ea4ea0b6dfe2" + integrity sha512-EpHfphxt7QjdHbbzV9vfamDP3Xug2jLdM37Z8uu8fIvkJYbAI+r5+MMXTc4g0OMyqWU+/Ik7M+GbA+c6K9Papw== + dependencies: + "@react-aria/interactions" "^3.15.1" + "@react-types/shared" "^3.18.1" + +"@react-types/listbox@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.4.2.tgz#13a217ca2c31e4e5c0ef46f00f770bf0d1b24726" + integrity sha512-qg980T+tl15pqgfuK8V6z+vsvsIrJEEPxcupQXP3T1O0LxWxJDakZHF0lV9qwfyB9XlnVSMZfkjDiZp9Wgf8QQ== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/menu@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.9.1.tgz#13b9c66a16ae0b5bff752295fe94f4f60c1dbd83" + integrity sha512-VOhp/gDrFqbVV5kiqFoJCba9mxyQH2eCdR26nK3Fn92K8AAGqKt1C0naKCgdAmGp2+qTveR94Iw0iyDfMt60og== + dependencies: + "@react-types/overlays" "^3.7.2" + "@react-types/shared" "^3.18.1" + +"@react-types/meter@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.3.2.tgz#f316eb4b47112137b0bbfc9e82b0f2814587c297" + integrity sha512-o21Zz+3LNjvBueMap+q2otGp5t2Xeb/lIMM4Y+v8j5XO+bLcHaAjdQB/TgKRe8iYFm3IqwpVtV9A38IWDtpLRQ== + dependencies: + "@react-types/progress" "^3.4.1" + "@react-types/shared" "^3.18.1" + +"@react-types/numberfield@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.4.2.tgz#6773e93b611131d45a4e5c4cac561945dc5ac7f3" + integrity sha512-SGzuuFf5wCSRPvpV+bnykiXSIt8pkpBBVp8tlygB66pQSBV7VLdUvWGohaayPSM+3Z+WkU+osgzYtGq5wh+C3Q== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/overlays@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.7.2.tgz#40881c6c6e05330e0ea8960646ca2371378b95c0" + integrity sha512-I/mm/xjJVJX2VC4UwNwzhsgVKh8eTHjE2NT6Ek70t/AMR/AT8i3m+eLYb4LEoRFFuZ0ctoJDLKkSCAP7nTkT0A== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/progress@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.4.1.tgz#3b45df4780b70573c27b316d557ce71b546e32bf" + integrity sha512-Y6cTvvJjbfFBeB7Zb3PizhhO3+YLWXpIP8opto15RWu11ktgZVMUgsnlsJgE3dFeoZ7UHwXdCYf8JOzBw5VPHA== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/radio@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.4.2.tgz#4a6a1f7ff11b71b6b69d13d28fd74de9c903df8c" + integrity sha512-SE6sjZjZbyuJMJNNdlhoutVr+QFRt1Vz7DZj4UaOswW5SD/Xb+xFdW8i6ETKdRN17am/5SC89ltWe0R3q0pVkA== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/searchfield@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.4.2.tgz#360ac97f52af5e2bb8e1a8a13e611fe9efc371fa" + integrity sha512-HQm++hIXVfEbjbRey6hYV/5hLEO6gtwt4Mft3u5I5BiT7yoQqQAD/8z9S8aUXDUU9KTrAKfL1DwrFQSkOsCWJA== + dependencies: + "@react-types/shared" "^3.18.1" + "@react-types/textfield" "^3.7.2" + +"@react-types/select@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.8.1.tgz#77d8ff3be70a5c342860469d71c8c23bbc1a877f" + integrity sha512-ByVKKwgpE3d08jI+Ibuom/qphlBiDKpVMwXgFgVZRAN2YvVrsix8arSo7kmXtzekz91qqDBqtt7DBCfT0E1WKw== + dependencies: + "@react-types/shared" "^3.18.1" + +"@react-types/shared@^3.18.1": + version "3.18.1" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.18.1.tgz#45bac7a1a433916d16535ea583d86a2b4c72ff8c" + integrity sha512-OpTYRFS607Ctfd6Tmhyk6t6cbFyDhO5K+etU35X50pMzpypo1b7vF0mkngEeTc0Xwl0e749ONZNPZskMyu5k8w== + +"@react-types/slider@^3.5.1": + version "3.5.1" + resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.5.1.tgz#bae46025de7d02a84918b3aca0e3ffd647e4fdf2" + integrity sha512-8+AMNexx7q7DqfAtQKC5tgnZdG/tIwG2tcEbFCfAQA09Djrt/xiMNz+mc7SsV1PWoWwVuSDFH9QqKPodOrJHDg== dependencies: - "@react-spring/shared" "~9.4.5" - "@react-spring/types" "~9.4.5" + "@react-types/shared" "^3.18.1" -"@react-spring/core@~9.4.5": - version "9.4.5" - resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.4.5.tgz#4616e1adc18dd10f5731f100ebdbe9518b89ba3c" - integrity sha512-83u3FzfQmGMJFwZLAJSwF24/ZJctwUkWtyPD7KYtNagrFeQKUH1I05ZuhmCmqW+2w1KDW1SFWQ43RawqfXKiiQ== +"@react-types/switch@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.3.2.tgz#af54e2dd8b599df3214360f593827c9033478ce4" + integrity sha512-L0XF4J43Q7HCAJXqseAk6RMteK6k1jQ0zrG05r6lSCkxaS9fGUlgLTCiFUsf07x0ADH1Xyc7PwpfJjyEr5A4tA== dependencies: - "@react-spring/animated" "~9.4.5" - "@react-spring/rafz" "~9.4.5" - "@react-spring/shared" "~9.4.5" - "@react-spring/types" "~9.4.5" + "@react-types/checkbox" "^3.4.4" + "@react-types/shared" "^3.18.1" -"@react-spring/rafz@~9.4.5": - version "9.4.5" - resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.4.5.tgz#84f809f287f2a66bbfbc66195db340482f886bd7" - integrity sha512-swGsutMwvnoyTRxvqhfJBtGM8Ipx6ks0RkIpNX9F/U7XmyPvBMGd3GgX/mqxZUpdlsuI1zr/jiYw+GXZxAlLcQ== +"@react-types/table@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.6.1.tgz#5c320f66a376dabc923cbddda3a19e9d4fb51c80" + integrity sha512-DeiiBZPZUO2kH40P10Bn9Y4SvDobUlH7Flgx2afL3tJirKMkS1SNDU/B+X9B5Duyd1D0okf1+PLVmi0NBqM4vg== + dependencies: + "@react-types/grid" "^3.1.8" + "@react-types/shared" "^3.18.1" -"@react-spring/shared@~9.4.5": - version "9.4.5" - resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.4.5.tgz#4c3ad817bca547984fb1539204d752a412a6d829" - integrity sha512-JhMh3nFKsqyag0KM5IIM8BQANGscTdd0mMv3BXsUiMZrcjQTskyfnv5qxEeGWbJGGar52qr5kHuBHtCjQOzniA== +"@react-types/tabs@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.0.tgz#d8230bac82fcd1dca414fbc1c17b769cef9c5bd8" + integrity sha512-uXDVXBBppb+9S8bhxF7LZhgptrF5ll25SX8/jrpnXOR0jpihq6K3fkSe5M/OBnGsybuyVGN7+Np5v7UUYrM5SQ== dependencies: - "@react-spring/rafz" "~9.4.5" - "@react-spring/types" "~9.4.5" + "@react-types/shared" "^3.18.1" -"@react-spring/types@~9.4.5": - version "9.4.5" - resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.4.5.tgz#9c71e5ff866b5484a7ef3db822bf6c10e77bdd8c" - integrity sha512-mpRIamoHwql0ogxEUh9yr4TP0xU5CWyZxVQeccGkHHF8kPMErtDXJlxyo0lj+telRF35XNihtPTWoflqtyARmg== +"@react-types/textfield@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.7.2.tgz#f23341e80b319b68f2298dd429ed2280ada0bbe1" + integrity sha512-TsZTf1+4Ve9QHm6mbXr26uLOA4QtZPgyjYgYclL2nHoOl67algeQIFxIVfdlNIKFFMOw5BtC6Mer0I3KUWtbOQ== + dependencies: + "@react-types/shared" "^3.18.1" -"@react-spring/web@9.4.5": - version "9.4.5" - resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.4.5.tgz#b92f05b87cdc0963a59ee149e677dcaff09f680e" - integrity sha512-NGAkOtKmOzDEctL7MzRlQGv24sRce++0xAY7KlcxmeVkR7LRSGkoXHaIfm9ObzxPMcPHQYQhf3+X9jepIFNHQA== +"@react-types/tooltip@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.1.tgz#131b0a6e28a1865b8977ce108cb7b069d29e5fd8" + integrity sha512-j1QbEX4RZ/uBQa9z1lBZ9bNUa20ji/UjwrIfTNyQm3wbezSZE0PWTQAkfxZdy3PQTBnVGOHSqxAP6iOS6NqOOQ== dependencies: - "@react-spring/animated" "~9.4.5" - "@react-spring/core" "~9.4.5" - "@react-spring/shared" "~9.4.5" - "@react-spring/types" "~9.4.5" + "@react-types/overlays" "^3.7.2" + "@react-types/shared" "^3.18.1" "@redux-devtools/extension@^3.2.3": version "3.2.5" @@ -2219,6 +4178,70 @@ "@babel/runtime" "^7.20.7" immutable "^4.2.2" +"@sentry-internal/tracing@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.57.0.tgz#cb761931b635f8f24c84be0eecfacb8516b20551" + integrity sha512-tpViyDd8AhQGYYhI94xi2aaDopXOPfL2Apwrtb3qirWkomIQ2K86W1mPmkce+B0cFOnW2Dxv/ZTFKz6ghjK75A== + dependencies: + "@sentry/core" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/browser@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.57.0.tgz#6e724c9eac680dba99ced0fdf81be8d1e3b3bceb" + integrity sha512-E0HaYYlaqHFiIRZXxcvOO8Odvlt+TR1vFFXzqUWXPOvDRxURglTOCQ3EN/u6bxtAGJ6y/Zc2obgihTtypuel/w== + dependencies: + "@sentry-internal/tracing" "7.57.0" + "@sentry/core" "7.57.0" + "@sentry/replay" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/core@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.57.0.tgz#65093d739c04f320a54395a21be955fcbe326acb" + integrity sha512-l014NudPH0vQlzybtXajPxYFfs9w762NoarjObC3gu76D1jzBBFzhdRelkGpDbSLNTIsKhEDDRpgAjBWJ9icfw== + dependencies: + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/react@^7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.57.0.tgz#cf91f0115bcd2a8306d6c8a39d8e8b53d4b21814" + integrity sha512-XGNTjIoCG3naSmCU8qObd+y+CqAB6NQkGWOp2yyBwp2inyKF2ehJvDh6bIQloBYq2TmOJDa4NfXdMrkilxaLFQ== + dependencies: + "@sentry/browser" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + hoist-non-react-statics "^3.3.2" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/replay@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.57.0.tgz#c8f7eae7b7edc9d32c3d2955b337f3b3c76dff39" + integrity sha512-pN4ryNS3J5EYbkXvR+O/+hseAJha7XDl8mPFtK0OGTHG10JzCi4tQJazblHQdpb5QBaMMPCeZ+isyfoQLDNXnw== + dependencies: + "@sentry/core" "7.57.0" + "@sentry/types" "7.57.0" + "@sentry/utils" "7.57.0" + +"@sentry/types@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.57.0.tgz#4fdb80cbd49ba034dd8d9be0c0005a016d5db3ce" + integrity sha512-D7ifoUfxuVCUyktIr5Gc+jXUbtcUMmfHdTtTbf1XCZHua5mJceK9wtl3YCg3eq/HK2Ppd52BKnTzEcS5ZKQM+w== + +"@sentry/utils@7.57.0": + version "7.57.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.57.0.tgz#8253c6fcf35138b4c424234b8da1596e11b98ad8" + integrity sha512-YXrkMCiNklqkXctn4mKYkrzNCf/dfVcRUQrkXjeBC+PHXbcpPyaJgInNvztR7Skl8lE3JPGPN4v5XhLxK1bUUg== + dependencies: + "@sentry/types" "7.57.0" + tslib "^2.4.1 || ^1.9.3" + "@serverless/utils@^6.0.2": version "6.8.2" resolved "https://registry.yarnpkg.com/@serverless/utils/-/utils-6.8.2.tgz#6ec34e8308b74f219cc80704e417c1a438629dd0" @@ -2267,6 +4290,13 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== +"@swc/helpers@^0.4.14": + version "0.4.14" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74" + integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw== + dependencies: + tslib "^2.4.0" + "@szmarczak/http-timer@^4.0.5": version "4.0.6" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" @@ -2274,6 +4304,18 @@ dependencies: defer-to-connect "^2.0.0" +"@tanstack/react-table@^8.5.22": + version "8.8.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.8.4.tgz#814acc520f8d7356d007b441a784c5a30154f516" + integrity sha512-5w2AoBnDBJYuUa80sLOqelcG/eJdGwIPFBRnEiU3RCAEeZ1QIhYse/0vzhTY8VAcTXa2sjWhXNDWci4VlktNmg== + dependencies: + "@tanstack/table-core" "8.8.4" + +"@tanstack/table-core@8.8.4": + version "8.8.4" + resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.8.4.tgz#4b6938c0531011afc0746a50ff9b3f772199be36" + integrity sha512-4gq0A/Qz/JFuclxPd1UnNi5P57vbVF10mPK743Iuv2ORLLgF/O/XkaYjYDGw5SHMof8CgiT/nfdJdlgHsOfRIg== + "@testing-library/jest-dom@^5.11.4": version "5.16.5" resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e" @@ -2339,6 +4381,89 @@ dependencies: "@types/node" "*" +"@types/d3-color@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-2.0.3.tgz#8bc4589073c80e33d126345542f588056511fe82" + integrity sha512-+0EtEjBfKEDtH9Rk3u3kLOUXM5F+iZK+WvASPb0MhIZl8J8NUvGeZRwKCXl+P3HkYx5TdU4YtcibpqHkSR9n7w== + +"@types/d3-delaunay@^5.3.0": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-5.3.1.tgz#47ae03af6b78cb3aa39d3d3c42ca71daca488aef" + integrity sha512-F6itHi2DxdatHil1rJ2yEFUNhejj8+0Acd55LZ6Ggwbdoks0+DxVY2cawNj16sjCBiWvubVlh6eBMVsYRNGLew== + +"@types/d3-format@^1.4.1": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-1.4.2.tgz#ea17bf559b71d9afd569ae9bfe4c544dab863baa" + integrity sha512-WeGCHAs7PHdZYq6lwl/+jsl+Nfc1J2W1kNcMeIMYzQsT6mtBDBgtJ/rcdjZ0k0rVIvqEZqhhuD5TK/v3P2gFHQ== + +"@types/d3-hierarchy@^1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz#50657f420d565a06c0b950a4b82eee0a369f2dea" + integrity sha512-AbStKxNyWiMDQPGDguG2Kuhlq1Sv539pZSxYbx4UZeYkutpPwXCcgyiRrlV4YH64nIOsKx7XVnOMy9O7rJsXkg== + +"@types/d3-path@^1": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.9.tgz#73526b150d14cd96e701597cbf346cfd1fd4a58c" + integrity sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ== + +"@types/d3-path@^2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-2.0.2.tgz#6052f38f6186319769dfabab61b5514b0e02c75c" + integrity sha512-3YHpvDw9LzONaJzejXLOwZ3LqwwkoXb9LI2YN7Hbd6pkGo5nIlJ09ul4bQhBN4hQZJKmUpX8HkVqbzgUKY48cg== + +"@types/d3-sankey@^0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@types/d3-sankey/-/d3-sankey-0.11.2.tgz#803214b11dc0a17db5d782fe9055cd92b06a5d75" + integrity sha512-U6SrTWUERSlOhnpSrgvMX64WblX1AxX6nEjI2t3mLK2USpQrnbwYYK+AS9SwiE7wgYmOsSSKoSdr8aoKBH0HgQ== + dependencies: + "@types/d3-shape" "^1" + +"@types/d3-scale-chromatic@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-2.0.1.tgz#495cbbae7273e0d0ff564cdc19aa6d2b9928da83" + integrity sha512-3EuZlbPu+pvclZcb1DhlymTWT2W+lYsRKBjvkH2ojDbCWDYavifqu1vYX9WGzlPgCgcS4Alhk1+zapXbGEGylQ== + +"@types/d3-scale@^3.2.3": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-3.3.2.tgz#18c94e90f4f1c6b1ee14a70f14bfca2bd1c61d06" + integrity sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ== + dependencies: + "@types/d3-time" "^2" + +"@types/d3-shape@^1": + version "1.3.8" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.3.8.tgz#c3c15ec7436b4ce24e38de517586850f1fea8e89" + integrity sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg== + dependencies: + "@types/d3-path" "^1" + +"@types/d3-shape@^2.0.0": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-2.1.3.tgz#35d397b9e687abaa0de82343b250b9897b8cacf3" + integrity sha512-HAhCel3wP93kh4/rq+7atLdybcESZ5bRHDEZUojClyZWsRuEMo3A52NGYJSh48SxfxEU6RZIVbZL2YFZ2OAlzQ== + dependencies: + "@types/d3-path" "^2" + +"@types/d3-time-format@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-2.3.1.tgz#87a30e4513b9d1d53b920327a361f87255bf3372" + integrity sha512-fck0Z9RGfIQn3GJIEKVrp15h9m6Vlg0d5XXeiE/6+CQiBmMDZxfR21XtjEPuDeg7gC3bBM0SdieA5XF3GW1wKA== + +"@types/d3-time-format@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-3.0.1.tgz#1680fb6c41ab3a85db261ede296626668592246a" + integrity sha512-5GIimz5IqaRsdnxs4YlyTZPwAMfALu/wA4jqSiuqgdbCxUZ2WjrnwANqOtoBJQgeaUTdYNfALJO0Yb0YrDqduA== + +"@types/d3-time@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.1.1.tgz#6cf3a4242c3bbac00440dfb8ba7884f16bedfcbf" + integrity sha512-ULX7LoqXTCYtM+tLYOaeAJK7IwCT+4Gxlm2MaH0ErKLi07R5lh8NHCAyWcDkCCmx1AfRcBEV6H9QE9R25uP7jw== + +"@types/d3-time@^2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-2.1.1.tgz#743fdc821c81f86537cbfece07093ac39b4bc342" + integrity sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg== + "@types/debug@^4.0.0": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" @@ -2445,6 +4570,11 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/js-cookie@^2.2.6": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" + integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA== + "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -2494,7 +4624,7 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.5": +"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.2", "@types/prop-types@^15.7.5": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== @@ -2516,6 +4646,13 @@ dependencies: "@types/react" "*" +"@types/react-lifecycles-compat@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/react-lifecycles-compat/-/react-lifecycles-compat-3.0.1.tgz#a0b1fe18cfb9435bd52737829a69cbe93faf32e2" + integrity sha512-4KiU5s1Go4xRbf7t6VxUUpBeN5PGjpjpBv9VvET4uiPHC500VNYBclU13f8ehHkHoZL39b2cfwHu6RzbV3b44A== + dependencies: + "@types/react" "*" + "@types/react-redux@^7.1.20": version "7.1.25" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.25.tgz#de841631205b24f9dfb4967dd4a7901e048f9a88" @@ -2526,7 +4663,7 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-transition-group@^4.2.0", "@types/react-transition-group@^4.4.5": +"@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.5": version "4.4.5" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416" integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA== @@ -2861,6 +4998,11 @@ resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== +"@xobotyi/scrollbar-width@^1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" + integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -3007,6 +5149,11 @@ antlr4@4.10.1: resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.10.1.tgz#6be8e3e1ead19ca82419ef0ffe974ef4efe4a793" integrity sha512-fmxidcOwmktzHUD+tz8y/zKLI/NfVAB0+MOvnFUBzo8ToFnphK8JY88oOJeRdhnTrAhjtu45bvxddzbb8nMeIA== +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -3015,6 +5162,13 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +append-transform@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" + integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg== + dependencies: + default-require-extensions "^3.0.0" + arch@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" @@ -3027,11 +5181,35 @@ archive-type@^4.0.0: dependencies: file-type "^4.2.0" +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== + +arg@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +aria-hidden@^1.1.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" + integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== + dependencies: + tslib "^2.0.0" + aria-query@^5.0.0: version "5.1.3" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" @@ -3133,6 +5311,23 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== +attr-accept@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" + integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== + +autoprefixer@^10.4.14: + 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.21.5" + caniuse-lite "^1.0.30001464" + fraction.js "^4.2.0" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -3148,6 +5343,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== +axios@^0.26.0: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + babel-loader@^8.2.3: version "8.3.0" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" @@ -3158,6 +5360,17 @@ babel-loader@^8.2.3: make-dir "^3.1.0" schema-utils "^2.6.5" +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + babel-plugin-macros@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" @@ -3279,6 +5492,11 @@ blob-util@^2.0.2: resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== +bluebird@3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" + integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== + bluebird@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -3344,6 +5562,16 @@ browserslist@^4.14.5, browserslist@^4.21.3, browserslist@^4.21.5: node-releases "^2.0.8" update-browserslist-db "^1.0.10" +browserslist@^4.21.9: + 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" + buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -3426,6 +5654,16 @@ cachedir@^2.3.0: resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== +caching-transform@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" + integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA== + dependencies: + hasha "^5.0.0" + make-dir "^3.0.0" + package-hash "^4.0.0" + write-file-atomic "^3.0.0" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -3439,7 +5677,12 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^5.3.1: +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== @@ -3449,10 +5692,15 @@ camelize@^1.0.0: resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3" integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== -caniuse-lite@^1.0.30001449: - version "1.0.30001453" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001453.tgz#6d3a1501622bf424a3cee5ad9550e640b0de3de8" - integrity sha512-R9o/uySW38VViaTrOtwfbFEiBFUh7ST3uIG4OEymIG3/uKdHDO4xk/FaqfUw0d+irSUyFPy3dZszf9VvSTPnsA== +caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: + version "1.0.30001474" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz#13b6fe301a831fe666cce8ca4ef89352334133d5" + integrity sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q== + +caniuse-lite@^1.0.30001503: + version "1.0.30001512" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz#7450843fb581c39f290305a83523c7a9ef0d4cb4" + integrity sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw== canvas-color-tracker@1: version "1.2.1" @@ -3471,6 +5719,14 @@ ccount@^2.0.0: resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3488,24 +5744,26 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== -change-emitter@^0.1.2: - version "0.1.6" - resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" - integrity sha512-YXzt1cQ4a2jqazhcuSWEOc1K2q8g9H6eWNsyZgi640LDzRWVQ2eDe+Y/kVdftH+vYdPF2rgDb3dLdpxE1jvAxw== +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== character-entities@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3531,6 +5789,11 @@ chokidar@^3.4.0, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chroma-js@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-2.4.2.tgz#dffc214ed0c11fa8eefca2c36651d8e57cbfb2b0" + integrity sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A== + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -3627,6 +5890,15 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -3648,7 +5920,7 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clsx@^1.0.4, clsx@^1.1.1, clsx@^1.2.1: +clsx@^1.1.1, clsx@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== @@ -3682,13 +5954,18 @@ colorette@^2.0.10, colorette@^2.0.14, colorette@^2.0.16, colorette@^2.0.19: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + comma-separated-tokens@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" @@ -3704,7 +5981,7 @@ commander@^2.20.0, commander@^2.8.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.1: +commander@^4.0.0, commander@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== @@ -3719,6 +5996,11 @@ commander@^9.4.1: resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== +common-path-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" + integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== + common-tags@^1.8.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -3786,19 +6068,26 @@ cookie@0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +copy-to-clipboard@^3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" + integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== + dependencies: + toggle-selection "^1.0.6" + core-js-compat@^3.25.1: - version "3.28.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.28.0.tgz#c08456d854608a7264530a2afa281fadf20ecee6" - integrity sha512-myzPgE7QodMg4nnd3K1TDoES/nADRStM8Gpz0D6nhkwbmwEnE0ZGJgoWsvQ722FR8D7xS0n0LV556RcEicjTyg== + version "3.30.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.30.0.tgz#99aa2789f6ed2debfa1df3232784126ee97f4d80" + integrity sha512-P5A2h/9mRYZFIAP+5Ab8ns6083IyVpSclU74UNvbGVQ8VM7n3n3/g2yF3AkKQ9NXz2O+ioxLbEWKnDtgsFamhg== dependencies: browserslist "^4.21.5" -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - integrity sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA== +core-js-pure@^3.23.3: + version "3.30.2" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.30.2.tgz#005a82551f4af3250dcfb46ed360fad32ced114e" + integrity sha512-p/npFUJXXBkCCTIlEGBdghofn00jWG6ZOtdoIXSJmAu2QBvN0IqpZXWweOytcwE6cfx8ZvVUy1vw8zxhe4Y2vg== -core-js@^2.4.0: +core-js@^2.4.0, core-js@^2.6.5: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== @@ -3813,6 +6102,11 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cosmiconfig-typescript-loader@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz#c4259ce474c9df0f32274ed162c0447c951ef073" + integrity sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q== + cosmiconfig@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" @@ -3824,6 +6118,16 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +cosmiconfig@^8.1.3: + version "8.1.3" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689" + integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw== + dependencies: + import-fresh "^3.2.1" + js-yaml "^4.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + crelt@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94" @@ -3845,11 +6149,34 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +css-blank-pseudo@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-5.0.2.tgz#3df5cd950f64de960974da05e76954fd3d7442f9" + integrity sha512-aCU4AZ7uEcVSUzagTlA9pHciz7aWPKA/YzrEkpdSopJ2pvhIxiQ5sYeMz1/KByxlIo4XBdvMNJAVKMg/GRnhfw== + dependencies: + postcss-selector-parser "^6.0.10" + css-color-keywords@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg== +css-has-pseudo@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-5.0.2.tgz#8798118c705d858b7aeb9d839a39edd901c1cc83" + integrity sha512-q+U+4QdwwB7T9VEW/LyO6CFrLAeLqOykC5mDqJXc7aKZAhDbq7BvGT13VGJe+IwBfdN2o3Xdw2kJ5IxwV1Sc9Q== + dependencies: + "@csstools/selector-specificity" "^2.0.1" + postcss-selector-parser "^6.0.10" + postcss-value-parser "^4.2.0" + +css-in-js-utils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz#640ae6a33646d401fc720c54fc61c42cd76ae2bb" + integrity sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A== + dependencies: + hyphenate-style-name "^1.0.3" + css-loader@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" @@ -3869,6 +6196,11 @@ css-loader@^3.6.0: schema-utils "^2.7.0" semver "^6.3.0" +css-prefers-color-scheme@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-8.0.2.tgz#a0671f54eb19ed0d30b952574c0af11ec355fb6d" + integrity sha512-OvFghizHJ45x7nsJJUSYLyQNTzsCU8yWjxAc/nhPQg1pbs18LMoET8N3kOweFDPy0JV0OSXN2iqRFhPBHYOeMA== + css-to-react-native@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32" @@ -3878,6 +6210,14 @@ css-to-react-native@^3.0.0: css-color-keywords "^1.0.0" postcss-value-parser "^4.0.2" +css-tree@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + css-vendor@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" @@ -3891,25 +6231,30 @@ css.escape@^1.5.1: resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== +cssdb@^7.5.3: + version "7.5.3" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.5.3.tgz#6bbd0c6a935919d7f78b8a3ce098faacda01ae8a" + integrity sha512-NQNRhrEnS6cW+RU/foLphb6xI/MDA70bI3Cy6VxJU8ilxgyTYz1X9zUzFGVTG5nGPylcKAGIt/UNc4deT56lQQ== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -csstype@^2.5.2: - version "2.6.21" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" - integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w== - -csstype@^3.0.2, csstype@^3.1.1: +csstype@^3.0.2, csstype@^3.0.6: version "3.1.1" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== -cypress@^9.5.3: - version "9.7.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-9.7.0.tgz#bf55b2afd481f7a113ef5604aa8b693564b5e744" - integrity sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q== +csstype@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + +cypress@^10.11.0: + version "10.11.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.11.0.tgz#e9fbdd7638bae3d8fb7619fd75a6330d11ebb4e8" + integrity sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -3930,7 +6275,7 @@ cypress@^9.5.3: dayjs "^1.10.4" debug "^4.3.2" enquirer "^2.3.6" - eventemitter2 "^6.4.3" + eventemitter2 "6.4.7" execa "4.1.0" executable "^4.1.1" extract-zip "2.0.1" @@ -4001,12 +6346,12 @@ d3-chord@3: dependencies: d3-path "1 - 3" -"d3-color@1 - 2", d3-color@^2.0.0: +"d3-color@1 - 2": version "2.0.0" resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== -"d3-color@1 - 3", d3-color@3: +"d3-color@1 - 3", d3-color@3, d3-color@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== @@ -4345,6 +6690,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +dayjs@1.11.8: + version "1.11.8" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.8.tgz#4282f139c8c19dd6d0c7bd571e30c2d0ba7698ea" + integrity sha512-LcgxzFoWMEPO7ggRv1Y2N31hUf2R0Vj7fuy/m+Bg1K8rr+KAs1AEy4y9jd5DXe8pbHgX+srkHNS7TH6Q6ZhYeQ== + dayjs@^1.10.4, dayjs@^1.11.7: version "1.11.7" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" @@ -4362,6 +6712,13 @@ debug@2.6.9: dependencies: ms "2.0.0" +debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -4369,12 +6726,10 @@ debug@^3.1.0, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decode-named-character-reference@^1.0.0: version "1.0.2" @@ -4478,6 +6833,13 @@ default-gateway@^6.0.3: dependencies: execa "^5.0.0" +default-require-extensions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.1.tgz#bfae00feeaeada68c2ae256c62540f60b80625bd" + integrity sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw== + dependencies: + strip-bom "^4.0.0" + defaults@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" @@ -4551,11 +6913,26 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-browser@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" + integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== + +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + diff-sequences@^29.4.3: version "29.4.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" @@ -4573,6 +6950,11 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -4617,11 +6999,6 @@ dom-to-image@^2.6.0: resolved "https://registry.yarnpkg.com/dom-to-image/-/dom-to-image-2.6.0.tgz#8a503608088c87b1c22f9034ae032e1898955867" integrity sha512-Dt0QdaHmLpjURjU7Tnu3AgYSF2LuOmksSGsUcE6ItvJoCWTBEmiMXcqBdNSAm9+QbbwD7JMoVsuuKX6ZVQv1qA== -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - duration@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/duration/-/duration-0.2.2.tgz#ddf149bc3bc6901150fe9017111d016b3357f529" @@ -4649,9 +7026,14 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.284: - version "1.4.299" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.299.tgz#faa2069cd4879a73e540e533178db5c618768d41" - integrity sha512-lQ7ijJghH6pCGbfWXr6EY+KYCMaRSjgsY925r1p/TlpSfVM1VjHTcn1gAc15VM4uwti283X6QtjPTXdpoSGiZQ== + version "1.4.352" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.352.tgz#be96bd7c2f4b980deebc9338a49a67430a33ed73" + integrity sha512-ikFUEyu5/q+wJpMOxWxTaEVk2M1qKqTGKKyfJmod1CPZxKfYnxVS41/GCBQg21ItBpZybyN8sNpRqCUGm+Zc4Q== + +electron-to-chromium@^1.4.431: + version "1.4.450" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.450.tgz#df232c961ee9bf4e8980f86e96a6e9f291720138" + integrity sha512-BLG5HxSELlrMx7dJ2s+8SFlsCtJp37Zpk2VAxyC6CZtbc+9AJeZHfYHbrlSgdXp6saQ8StMqOTEDaBKgA7u1sw== emoji-regex@^8.0.0: version "8.0.0" @@ -4673,13 +7055,6 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -encoding@^0.1.11: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -4714,44 +7089,42 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error-stack-parser@^2.0.6: + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== + dependencies: + stackframe "^1.3.4" + es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== + version "1.20.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861" + integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA== dependencies: - available-typed-arrays "^1.0.5" call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" function-bind "^1.1.1" function.prototype.name "^1.1.5" get-intrinsic "^1.1.3" get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" has "^1.0.3" has-property-descriptors "^1.0.0" - has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" + internal-slot "^1.0.3" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" is-shared-array-buffer "^1.0.2" is-string "^1.0.7" - is-typed-array "^1.1.10" is-weakref "^1.0.2" object-inspect "^1.12.2" object-keys "^1.1.1" object.assign "^4.1.4" regexp.prototype.flags "^1.4.3" safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" es-get-iterator@^1.1.2: version "1.1.3" @@ -4773,15 +7146,6 @@ es-module-lexer@^0.9.0: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - es-shim-unscopables@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" @@ -4807,6 +7171,11 @@ es5-ext@^0.10.12, es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.49, es5-ext@ es6-symbol "^3.1.3" next-tick "^1.1.0" +es6-error@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + es6-iterator@^2.0.3, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" @@ -5039,6 +7408,11 @@ espree@^9.4.0: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + esquery@^1.4.0: version "1.4.2" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.2.tgz#c6d3fee05dd665808e2ad870631f221f5617b1d1" @@ -5081,10 +7455,10 @@ event-emitter@^0.3.5: d "1" es5-ext "~0.10.14" -eventemitter2@^6.4.3: - version "6.4.9" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" - integrity sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg== +eventemitter2@6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" + integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== eventemitter3@^4.0.0: version "4.0.7" @@ -5258,7 +7632,18 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.9: +fast-glob@^3.1.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0" + integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-glob@^3.2.12, fast-glob@^3.2.9: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== @@ -5279,11 +7664,26 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-loops@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-loops/-/fast-loops-1.1.3.tgz#ce96adb86d07e7bf9b4822ab9c6fac9964981f75" + integrity sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g== + +fast-shallow-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" + integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== + fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== +fastest-stable-stringify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76" + integrity sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q== + fastq@^1.6.0: version "1.15.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" @@ -5291,6 +7691,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fault@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + faye-websocket@^0.11.3: version "0.11.4" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" @@ -5303,19 +7710,6 @@ fbjs-css-vars@^1.0.0: resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== -fbjs@^0.8.1: - version "0.8.18" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.18.tgz#9835e0addb9aca2eff53295cd79ca1cfc7c9662a" - integrity sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA== - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.30" - fbjs@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" @@ -5363,6 +7757,13 @@ file-saver@^2.0.5: resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA== +file-selector@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc" + integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw== + dependencies: + tslib "^2.4.0" + file-type@^16.5.4: version "16.5.4" resolved "https://registry.yarnpkg.com/file-type/-/file-type-16.5.4.tgz#474fb4f704bee427681f98dd390058a172a6c2fd" @@ -5435,7 +7836,7 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-cache-dir@^3.3.1: +find-cache-dir@^3.2.0, find-cache-dir@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== @@ -5464,7 +7865,7 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@^4.0.0: +find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -5493,7 +7894,14 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -follow-redirects@^1.0.0: +focus-lock@^0.11.6: + version "0.11.6" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.11.6.tgz#e8821e21d218f03e100f7dc27b733f9c4f61e683" + integrity sha512-KSuV3ur4gf2KqMNoZx3nXNVhqCkn42GuTYCX4tXPEwf0MjpFQmNMiN6m7dXaUXgIoivL6/65agoUMg4RLS0Vbg== + dependencies: + tslib "^2.0.3" + +follow-redirects@^1.0.0, follow-redirects@^1.14.8: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== @@ -5525,11 +7933,28 @@ force-graph@^1.43: kapsule "^1.13" lodash.throttle "4" +foreground-child@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" + integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^3.0.2" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -5539,17 +7964,27 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +format@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" + integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -fromentries@^1.3.2: +fromentries@^1.2.0, fromentries@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg== @@ -5632,6 +8067,11 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" @@ -5641,6 +8081,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + get-stream@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" @@ -5702,7 +8147,19 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^7.1.3, glob@^7.2.0: +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -5721,14 +8178,6 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" -global@^4.3.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -5741,12 +8190,17 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== +globby@11.0.4: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== dependencies: - define-properties "^1.1.3" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" globby@^11.1.0: version "11.1.0" @@ -5789,6 +8243,11 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +graceful-fs@^4.1.15: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + grapheme-splitter@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" @@ -5821,11 +8280,6 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" @@ -5845,15 +8299,39 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasha@^5.0.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.2.tgz#a48477989b3b327aea3c04f53096d816d97522a1" + integrity sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ== + dependencies: + is-stream "^2.0.0" + type-fest "^0.8.0" + +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + hast-util-whitespace@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== -hoist-non-react-statics@^2.3.1: - version "2.5.5" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" - integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +highlight.js@^10.4.1, highlight.js@~10.7.0: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" @@ -5872,11 +8350,16 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-entities@^2.3.2: +html-entities@^2.1.0, html-entities@^2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + http-cache-semantics@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" @@ -5982,7 +8465,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.6, iconv-lite@^0.6.2, iconv-lite@^0.6.3: +iconv-lite@0.6, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -6001,7 +8484,7 @@ ieee754@^1.1.13, ieee754@^1.2.1: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.1.8, ignore@^5.2.0: +ignore@^5.1.4, ignore@^5.1.8, ignore@^5.2.0: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== @@ -6070,6 +8553,14 @@ inline-style-parser@0.1.1: resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== +inline-style-prefixer@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz#4290ed453ab0e4441583284ad86e41ad88384f44" + integrity sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg== + dependencies: + css-in-js-utils "^3.1.0" + fast-loops "^1.1.3" + inquirer@^8.2.5: version "8.2.5" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" @@ -6115,6 +8606,16 @@ interpret@^2.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +intl-messageformat@^10.1.0: + version "10.5.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.0.tgz#86d11b15913ac954075b25253f5e669359f89538" + integrity sha512-AvojYuOaRb6r2veOKfTVpxH9TrmjSdc5iR9R5RgBwrDZYSmAAFVT+QLbW3C4V7Qsg0OguMp67Q/EoUkxZzXRGw== + dependencies: + "@formatjs/ecma402-abstract" "1.17.0" + "@formatjs/fast-memoize" "2.2.0" + "@formatjs/icu-messageformat-parser" "2.6.0" + tslib "^2.4.0" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -6125,6 +8626,19 @@ ipaddr.js@^2.0.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -6134,12 +8648,12 @@ is-arguments@^1.1.1: has-tostringtag "^1.0.0" is-array-buffer@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" - integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.0" is-typed-array "^1.1.10" is-arrayish@^0.2.1: @@ -6200,6 +8714,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -6227,6 +8746,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + is-in-browser@^1.0.2, is-in-browser@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" @@ -6324,7 +8848,7 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" -is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== @@ -6353,7 +8877,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.9: +is-typed-array@^1.1.10: version "1.1.10" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== @@ -6364,7 +8888,7 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" -is-typedarray@~1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== @@ -6394,6 +8918,11 @@ is-weakset@^2.0.1: call-bind "^1.0.2" get-intrinsic "^1.1.1" +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -6426,19 +8955,87 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - integrity sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA== - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== +istanbul-lib-coverage@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-hook@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" + integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ== + dependencies: + append-transform "^2.0.0" + +istanbul-lib-instrument@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-processinfo@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz#366d454cd0dcb7eb6e0e419378e60072c8626169" + integrity sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg== + dependencies: + archy "^1.0.0" + cross-spawn "^7.0.3" + istanbul-lib-coverage "^3.2.0" + p-map "^3.0.0" + rimraf "^3.0.0" + uuid "^8.3.2" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + jerrypick@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/jerrypick/-/jerrypick-1.1.1.tgz#db0b15841a53cfe492de2db9544eecf8de73203c" @@ -6505,6 +9102,16 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" +jiti@^1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd" + integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg== + +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + js-sdsl@^4.1.4: version "4.3.0" resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" @@ -6515,13 +9122,21 @@ js-sdsl@^4.1.4: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -6603,7 +9218,7 @@ jsprim@^2.0.2: json-schema "0.4.0" verror "1.10.0" -jss-plugin-camel-case@^10.5.1: +jss-plugin-camel-case@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz#27ea159bab67eb4837fa0260204eb7925d4daa1c" integrity sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw== @@ -6612,7 +9227,7 @@ jss-plugin-camel-case@^10.5.1: hyphenate-style-name "^1.0.3" jss "10.10.0" -jss-plugin-default-unit@^10.5.1: +jss-plugin-default-unit@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz#db3925cf6a07f8e1dd459549d9c8aadff9804293" integrity sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ== @@ -6620,7 +9235,7 @@ jss-plugin-default-unit@^10.5.1: "@babel/runtime" "^7.3.1" jss "10.10.0" -jss-plugin-global@^10.5.1: +jss-plugin-global@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz#1c55d3c35821fab67a538a38918292fc9c567efd" integrity sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A== @@ -6628,7 +9243,7 @@ jss-plugin-global@^10.5.1: "@babel/runtime" "^7.3.1" jss "10.10.0" -jss-plugin-nested@^10.5.1: +jss-plugin-nested@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz#db872ed8925688806e77f1fc87f6e62264513219" integrity sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA== @@ -6637,7 +9252,7 @@ jss-plugin-nested@^10.5.1: jss "10.10.0" tiny-warning "^1.0.2" -jss-plugin-props-sort@^10.5.1: +jss-plugin-props-sort@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz#67f4dd4c70830c126f4ec49b4b37ccddb680a5d7" integrity sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg== @@ -6645,7 +9260,7 @@ jss-plugin-props-sort@^10.5.1: "@babel/runtime" "^7.3.1" jss "10.10.0" -jss-plugin-rule-value-function@^10.5.1: +jss-plugin-rule-value-function@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz#7d99e3229e78a3712f78ba50ab342e881d26a24b" integrity sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g== @@ -6654,7 +9269,7 @@ jss-plugin-rule-value-function@^10.5.1: jss "10.10.0" tiny-warning "^1.0.2" -jss-plugin-vendor-prefixer@^10.5.1: +jss-plugin-vendor-prefixer@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz#c01428ef5a89f2b128ec0af87a314d0c767931c7" integrity sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg== @@ -6663,7 +9278,7 @@ jss-plugin-vendor-prefixer@^10.5.1: css-vendor "^2.0.8" jss "10.10.0" -jss@10.10.0, jss@^10.5.1: +jss@10.10.0, jss@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss/-/jss-10.10.0.tgz#a75cc85b0108c7ac8c7b7d296c520a3e4fbc6ccc" integrity sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw== @@ -6710,6 +9325,11 @@ kleur@^4.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== +klona@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" + integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== + lazy-ass@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" @@ -6738,6 +9358,11 @@ lilconfig@2.0.6: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +lilconfig@^2.0.5, lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -6804,7 +9429,7 @@ loader-utils@^1.2.3: emojis-list "^3.0.0" json5 "^1.0.1" -loader-utils@^2.0.0, loader-utils@^2.0.3: +loader-utils@^2.0.0, loader-utils@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== @@ -6835,11 +9460,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash-es@^4.17.15: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -6850,6 +9470,11 @@ lodash.find@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" integrity sha512-yaRZoAV3Xq28F1iafWN1+a0rflOej93l1DQUejs3SZ41h2O9UJBoS9aueGjPDgAl4B6tPC0NuuchLKaDQQ3Isg== +lodash.flattendeep@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" + integrity sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ== + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -6880,7 +9505,7 @@ lodash.throttle@4: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== -lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.21: +lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6947,6 +9572,14 @@ lowercase-keys@^2.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lowlight@^1.17.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" + integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw== + dependencies: + fault "^1.0.0" + highlight.js "~10.7.0" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -6983,7 +9616,7 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.2, make-dir@^3.1.0: +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -6995,21 +9628,6 @@ markdown-table@^3.0.0: resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd" integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw== -material-colors@^1.2.1: - version "1.2.6" - resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" - integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== - -material-ui-color-picker@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/material-ui-color-picker/-/material-ui-color-picker-3.5.1.tgz#2f33f02a0a22647b135af848662409cad15f56e5" - integrity sha512-0mxnmfpl31m6ton13SbwWy3uUqQtmzV0bZl+pEK9lD+4daYB4+FeM05IW0wNU9pAum6JNT7ddYBUQ0tyDA1kvQ== - dependencies: - "@material-ui/styles" "^4.8.2" - prop-types "^15.7.2" - react-color "^2.18.0" - recompose "^0.30.0" - mdast-util-definitions@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" @@ -7142,11 +9760,14 @@ mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: zwitch "^2.0.0" mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz#db859050d79d48cf9896d294de06f3ede7474d16" - integrity sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA== - dependencies: - "@types/mdast" "^3.0.0" + version "3.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9" + integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA== + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== media-typer@0.3.0: version "0.3.0" @@ -7160,6 +9781,11 @@ memfs@^3.4.3: dependencies: fs-monkey "^1.0.3" +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + memoizee@^0.4.14, memoizee@^0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" @@ -7519,13 +10145,6 @@ mimic-response@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== - dependencies: - dom-walk "^0.1.0" - min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -7536,7 +10155,7 @@ minimalistic-assert@^1.0.0: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -7575,10 +10194,15 @@ ms@2.1.3, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mui-nested-menu@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/mui-nested-menu/-/mui-nested-menu-3.2.0.tgz#2797ff5a573e6374ff093f1aa88a03096ba41d00" - integrity sha512-3js6P2RHkexTZPRFYY5VnkVAncmAWVcZrVX2lqcWRF2X+LjF7v6JmXf3tZHl6w7A2DFbJW5vU1EaUOa48W5Rlg== +mui-color@^2.0.0-beta.2: + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/mui-color/-/mui-color-2.0.0-beta.2.tgz#0a3ea2aa436b3be6a24a8743eb451e662a986944" + integrity sha512-M6wM2t6lOKlQ8eVrF1wu4QSNq/V4jMhuD5wR9+imK8qr9fn953puXjCJNlvTXnU4N+ygxXwQZpunW4pQwWDLug== + +mui-nested-menu@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/mui-nested-menu/-/mui-nested-menu-3.2.1.tgz#22fbae0554453aa7c8e22c1755573ff8104371d3" + integrity sha512-rlSLejTPTK9sUOOqjYp00aFneClx/gWFL8NDilR1I37Ad8DLm32gMkLX3fkmuQt1KhUyWK/vt3I5gcQPraXfZw== multicast-dns@^7.2.5: version "7.2.5" @@ -7593,6 +10217,34 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nano-css@^5.3.1: + version "5.3.5" + resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.5.tgz#3075ea29ffdeb0c7cb6d25edb21d8f7fa8e8fe8e" + integrity sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg== + dependencies: + css-tree "^1.1.2" + csstype "^3.0.6" + fastest-stable-stringify "^2.0.2" + inline-style-prefixer "^6.0.0" + rtl-css-js "^1.14.0" + sourcemap-codec "^1.4.8" + stacktrace-js "^2.0.2" + stylis "^4.0.6" + +nanoid@^3.3.4, nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -7672,14 +10324,6 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - node-fetch@^2.6.7: version "2.6.9" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" @@ -7692,6 +10336,18 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-preload@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" + integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ== + dependencies: + process-on-spawn "^1.0.0" + +node-releases@^2.0.12: + version "2.0.12" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039" + integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== + node-releases@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -7702,6 +10358,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -7721,11 +10382,49 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" +nyc@15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02" + integrity sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A== + dependencies: + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + caching-transform "^4.0.0" + convert-source-map "^1.7.0" + decamelize "^1.2.0" + find-cache-dir "^3.2.0" + find-up "^4.1.0" + foreground-child "^2.0.0" + get-package-type "^0.1.0" + glob "^7.1.6" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-hook "^3.0.0" + istanbul-lib-instrument "^4.0.0" + istanbul-lib-processinfo "^2.0.2" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + make-dir "^3.0.0" + node-preload "^0.2.1" + p-map "^3.0.0" + process-on-spawn "^1.0.0" + resolve-from "^5.0.0" + rimraf "^3.0.0" + signal-exit "^3.0.2" + spawn-wrap "^2.0.0" + test-exclude "^6.0.0" + yargs "^15.0.2" + object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + object-inspect@^1.12.2, object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" @@ -7836,6 +10535,14 @@ open@^8.0.9, open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" +openai@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/openai/-/openai-3.3.0.tgz#a6408016ad0945738e1febf43f2fccca83a3f532" + integrity sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ== + dependencies: + axios "^0.26.0" + form-data "^4.0.0" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -7925,6 +10632,13 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -7952,6 +10666,16 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-hash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506" + integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ== + dependencies: + graceful-fs "^4.1.15" + hasha "^5.0.0" + lodash.flattendeep "^4.4.0" + release-zalgo "^1.0.0" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -7959,6 +10683,18 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + parse-json@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -8076,7 +10812,7 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== -pirates@^4.0.5: +pirates@^4.0.1, pirates@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== @@ -8095,10 +10831,172 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -popper.js@1.16.1-lts: - version "1.16.1-lts" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" - integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA== +postcss-attribute-case-insensitive@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-6.0.2.tgz#e843091859323342e461878d201ee70278809e01" + integrity sha512-IRuCwwAAQbgaLhxQdQcIIK0dCVXg3XDUnzgKD8iwdiYdwU4rMWRWyl/W9/0nA4ihVpq5pyALiHB2veBJ0292pw== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-clamp@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-clamp/-/postcss-clamp-4.1.0.tgz#7263e95abadd8c2ba1bd911b0b5a5c9c93e02363" + integrity sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-functional-notation@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-5.0.2.tgz#6d03c928aa3a13487703af86c301bdcd501e7430" + integrity sha512-M6ygxWOyd6eWf3sd1Lv8xi4SeF4iBPfJvkfMU4ITh8ExJc1qhbvh/U8Cv/uOvBgUVOMDdScvCdlg8+hREQzs7w== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-hex-alpha@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-9.0.2.tgz#6d3ed50342802469880981a1999515d003ff7d79" + integrity sha512-SfPjgr//VQ/DOCf80STIAsdAs7sbIbxATvVmd+Ec7JvR8onz9pjawhq3BJM3Pie40EE3TyB0P6hft16D33Nlyg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-color-rebeccapurple@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-8.0.2.tgz#c0f2dcf1ef4dd393314920aa181cca8c390a2648" + integrity sha512-xWf/JmAxVoB5bltHpXk+uGRoGFwu4WDAR7210el+iyvTdqiKpDhtcT8N3edXMoVJY0WHFMrKMUieql/wRNiXkw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-custom-media@^9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-9.1.2.tgz#0e9c34b0b5325edc2c5f42f47543cb64d777764b" + integrity sha512-osM9g4UKq4XKimAC7RAXroqi3BXpxfwTswAJQiZdrBjWGFGEyxQrY5H2eDWI8F+MEvEUfYDxA8scqi3QWROCSw== + dependencies: + "@csstools/cascade-layer-name-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.0" + "@csstools/css-tokenizer" "^2.0.0" + "@csstools/media-query-list-parser" "^2.0.0" + +postcss-custom-properties@^13.1.4: + version "13.1.4" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-13.1.4.tgz#590e5770137011001602806da51243b6c82c1cde" + integrity sha512-iSAdaZrM3KMec8cOSzeTUNXPYDlhqsMJHpt62yrjwG6nAnMtRHPk5JdMzGosBJtqEahDolvD5LNbcq+EZ78o5g== + dependencies: + "@csstools/cascade-layer-name-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.0" + "@csstools/css-tokenizer" "^2.0.0" + postcss-value-parser "^4.2.0" + +postcss-custom-selectors@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-7.1.2.tgz#e100e9dd628d969a651d7d310cdfd25b27b58d4b" + integrity sha512-jX7VlE3jrgfBIOfxiGNRFq81xUoHSZhvxhQurzE7ZFRv+bUmMwB7/XnA0nNlts2CwNtbXm4Ozy0ZAYKHlCRmBQ== + dependencies: + "@csstools/cascade-layer-name-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.0" + "@csstools/css-tokenizer" "^2.0.0" + postcss-selector-parser "^6.0.4" + +postcss-dir-pseudo-class@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-7.0.2.tgz#71618b7eb4abe067845d11b3c8f322760c9b3e88" + integrity sha512-cMnslilYxBf9k3qejnovrUONZx1rXeUZJw06fgIUBzABJe3D2LiLL5WAER7Imt3nrkaIgG05XZBztueLEf5P8w== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-double-position-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-4.0.2.tgz#855a23201f26be447210504e9b668429cbf4640c" + integrity sha512-GXL1RmFREDK4Q9aYvI2RhVrA6a6qqSMQQ5ke8gSH1xgV6exsqbcJpIumC7AOgooH6/WIG3/K/T8xxAiVHy/tJg== + dependencies: + "@csstools/postcss-progressive-custom-properties" "^2.0.0" + postcss-value-parser "^4.2.0" + +postcss-focus-visible@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-8.0.2.tgz#a7ac26ffe3e9c2bd17d7200d75e2d79ee8110891" + integrity sha512-f/Vd+EC/GaKElknU59esVcRYr/Y3t1ZAQyL4u2xSOgkDy4bMCmG7VP5cGvj3+BTLNE9ETfEuz2nnt4qkZwTTeA== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-focus-within@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-7.0.2.tgz#5d2c866030e66ed22b204c9506de640943310b1c" + integrity sha512-AHAJ89UQBcqBvFgQJE9XasGuwMNkKsGj4D/f9Uk60jFmEBHpAL14DrnSk3Rj+SwZTr/WUG+mh+Rvf8fid/346w== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-font-variant@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz#efd59b4b7ea8bb06127f2d031bfbb7f24d32fa66" + integrity sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA== + +postcss-gap-properties@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-4.0.1.tgz#0347d6a84a46bfbe88bedc542cc4b354e04a8338" + integrity sha512-V5OuQGw4lBumPlwHWk/PRfMKjaq/LTGR4WDTemIMCaMevArVfCCA9wBJiL1VjDAd+rzuCIlkRoRvDsSiAaZ4Fg== + +postcss-image-set-function@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-5.0.2.tgz#088e0f535f43e74d6ea8033ff7b0482e2735ea6e" + integrity sha512-Sszjwo0ubETX0Fi5MvpYzsONwrsjeabjMoc5YqHvURFItXgIu3HdCjcVuVKGMPGzKRhgaknmdM5uVWInWPJmeg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42" + integrity sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ== + +postcss-js@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== + dependencies: + camelcase-css "^2.0.1" + +postcss-lab-function@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-5.2.0.tgz#7504de96d5bd21177af241fe7601b5151f2df1a4" + integrity sha512-ie/k0xFCib22LV56jZoygLuWfM4J4migb89QnEXOjORGh6UwsDVSPW/x+P2MYS+AKFfZ5Npcu5HYEzYcezAAag== + dependencies: + "@csstools/css-color-parser" "^1.0.0" + "@csstools/css-parser-algorithms" "^2.0.1" + "@csstools/css-tokenizer" "^2.1.0" + "@csstools/postcss-progressive-custom-properties" "^2.0.0" + +postcss-load-config@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd" + integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA== + dependencies: + lilconfig "^2.0.5" + yaml "^2.1.1" + +postcss-loader@^7.2.4: + version "7.2.4" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.2.4.tgz#2884f4ca172de633b2cf1f93dc852968f0632ba9" + integrity sha512-F88rpxxNspo5hatIc+orYwZDtHFaVFOSIVAx+fBfJC1GmhWbVmPWtmg2gXKE1OxJbneOSGn8PWdIwsZFcruS+w== + dependencies: + cosmiconfig "^8.1.3" + cosmiconfig-typescript-loader "^4.3.0" + klona "^2.0.6" + semver "^7.3.8" + +postcss-logical@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-6.1.0.tgz#c33ae75d3edaea7eb821e76dc4e6d0ecedc3200d" + integrity sha512-qb1+LpClhYjxac8SfOcWotnY3unKZesDqIOm+jnGt8rTl7xaIWpE2bPGZHxflOip1E/4ETo79qlJyRL3yrHn1g== + dependencies: + postcss-value-parser "^4.2.0" postcss-modules-extract-imports@^2.0.0: version "2.0.0" @@ -8133,7 +11031,126 @@ postcss-modules-values@^3.0.0: icss-utils "^4.0.0" postcss "^7.0.6" -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: +postcss-nested@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c" + integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ== + dependencies: + postcss-selector-parser "^6.0.11" + +postcss-nesting@^11.2.1: + version "11.2.2" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-11.2.2.tgz#ddedfea5a1fdcd8d753298d82297ad15d5640c0f" + integrity sha512-aOTiUniAB1bcPE6GGiynWRa6PZFPhOTAm5q3q5cem6QeSijIHHkWr6gs65ukCZMXeak8yXeZVbBJET3VM+HlhA== + dependencies: + "@csstools/selector-specificity" "^2.0.0" + postcss-selector-parser "^6.0.10" + +postcss-opacity-percentage@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-2.0.0.tgz#c0a56060cd4586e3f954dbde1efffc2deed53002" + integrity sha512-lyDrCOtntq5Y1JZpBFzIWm2wG9kbEdujpNt4NLannF+J9c8CgFIzPa80YQfdza+Y+yFfzbYj/rfoOsYsooUWTQ== + +postcss-overflow-shorthand@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-4.0.1.tgz#cb61ca24d8c4e1dbf14d85181b017cfa6953aa34" + integrity sha512-HQZ0qi/9iSYHW4w3ogNqVNr2J49DHJAl7r8O2p0Meip38jsdnRPgiDW7r/LlLrrMBMe3KHkvNtAV2UmRVxzLIg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-page-break@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-3.0.4.tgz#7fbf741c233621622b68d435babfb70dd8c1ee5f" + integrity sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ== + +postcss-place@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-8.0.1.tgz#408d7a27e99192df51c95fe62a3a34def62aa66a" + integrity sha512-Ow2LedN8sL4pq8ubukO77phSVt4QyCm35ZGCYXKvRFayAwcpgB0sjNJglDoTuRdUL32q/ZC1VkPBo0AOEr4Uiw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-preset-env@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-8.3.0.tgz#a310f9029a62b5189cf1e6afd1970ccbf8c96fdc" + integrity sha512-VFc/bhwRo37RoTVzCTCKDJLw0lwsqLRCTc7dkJkfs9S7XXfTbk7QkhbMWHd2L+iZsAsE5yqdSRBZ41/Q828TbA== + dependencies: + "@csstools/postcss-cascade-layers" "^3.0.1" + "@csstools/postcss-color-function" "^2.1.0" + "@csstools/postcss-color-mix-function" "^1.0.0" + "@csstools/postcss-font-format-keywords" "^2.0.2" + "@csstools/postcss-gradients-interpolation-method" "^3.0.1" + "@csstools/postcss-hwb-function" "^2.2.0" + "@csstools/postcss-ic-unit" "^2.0.2" + "@csstools/postcss-is-pseudo-class" "^3.1.1" + "@csstools/postcss-logical-float-and-clear" "^1.0.1" + "@csstools/postcss-logical-resize" "^1.0.1" + "@csstools/postcss-logical-viewport-units" "^1.0.2" + "@csstools/postcss-media-minmax" "^1.0.0" + "@csstools/postcss-media-queries-aspect-ratio-number-values" "^1.0.1" + "@csstools/postcss-nested-calc" "^2.0.2" + "@csstools/postcss-normalize-display-values" "^2.0.1" + "@csstools/postcss-oklab-function" "^2.2.0" + "@csstools/postcss-progressive-custom-properties" "^2.1.0" + "@csstools/postcss-scope-pseudo-class" "^2.0.2" + "@csstools/postcss-stepped-value-functions" "^2.1.0" + "@csstools/postcss-text-decoration-shorthand" "^2.2.1" + "@csstools/postcss-trigonometric-functions" "^2.1.0" + "@csstools/postcss-unset-value" "^2.0.1" + autoprefixer "^10.4.14" + browserslist "^4.21.5" + css-blank-pseudo "^5.0.2" + css-has-pseudo "^5.0.2" + css-prefers-color-scheme "^8.0.2" + cssdb "^7.5.3" + postcss-attribute-case-insensitive "^6.0.2" + postcss-clamp "^4.1.0" + postcss-color-functional-notation "^5.0.2" + postcss-color-hex-alpha "^9.0.2" + postcss-color-rebeccapurple "^8.0.2" + postcss-custom-media "^9.1.2" + postcss-custom-properties "^13.1.4" + postcss-custom-selectors "^7.1.2" + postcss-dir-pseudo-class "^7.0.2" + postcss-double-position-gradients "^4.0.2" + postcss-focus-visible "^8.0.2" + postcss-focus-within "^7.0.2" + postcss-font-variant "^5.0.0" + postcss-gap-properties "^4.0.1" + postcss-image-set-function "^5.0.2" + postcss-initial "^4.0.1" + postcss-lab-function "^5.2.0" + postcss-logical "^6.1.0" + postcss-nesting "^11.2.1" + postcss-opacity-percentage "^2.0.0" + postcss-overflow-shorthand "^4.0.1" + postcss-page-break "^3.0.4" + postcss-place "^8.0.1" + postcss-pseudo-class-any-link "^8.0.2" + postcss-replace-overflow-wrap "^4.0.0" + postcss-selector-not "^7.0.1" + postcss-value-parser "^4.2.0" + +postcss-pseudo-class-any-link@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-8.0.2.tgz#f5738503f2045de0c4dc216eca99bd835f74e42e" + integrity sha512-FYTIuRE07jZ2CW8POvctRgArQJ43yxhr5vLmImdKUvjFCkR09kh8pIdlCwdx/jbFm7MiW4QP58L4oOUv3grQYA== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-replace-overflow-wrap@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz#d2df6bed10b477bf9c52fab28c568b4b29ca4319" + integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw== + +postcss-selector-not@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-7.0.1.tgz#8142e90c8eb6c8c5faecb3e9d96d4353d02e94fb" + integrity sha512-1zT5C27b/zeJhchN7fP0kBr16Cc61mu7Si9uWWLoA3Px/D9tIJPKchJCkUH3tPO5D0pCFmGeApAv8XpXBQJ8SQ== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: version "6.0.11" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== @@ -8141,7 +11158,7 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: +postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== @@ -8154,6 +11171,24 @@ postcss@^7.0.14, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: picocolors "^0.2.1" source-map "^0.6.1" +postcss@^8.4.21: + version "8.4.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" + integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.23: + version "8.4.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab" + integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -8178,11 +11213,28 @@ pretty-format@^29.0.0, pretty-format@^29.4.3: ansi-styles "^5.0.0" react-is "^18.0.0" +prismjs@^1.27.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" + integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== + +prismjs@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" + integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process-on-spawn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" + integrity sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg== + dependencies: + fromentries "^1.2.0" + process-utils@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/process-utils/-/process-utils-4.0.0.tgz#3e5b204e1d38e62fe39ef3144664a1fe94097b9e" @@ -8193,11 +11245,6 @@ process-utils@^4.0.0: memoizee "^0.4.14" type "^2.1.0" -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -8205,7 +11252,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8, prop-types@^15.8.1: +prop-types@15.x, prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -8214,6 +11261,13 @@ prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.1, pr object-assign "^4.1.1" react-is "^16.13.1" +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + property-information@^6.0.0: version "6.2.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.2.0.tgz#b74f522c31c097b5149e3c3cb8d7f3defd986a1d" @@ -8296,18 +11350,59 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -react-color@^2.18.0: - version "2.19.3" - resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d" - integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA== +re-resizable@^6.9.9: + version "6.9.9" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" + integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA== + +react-aria@^3.25.0: + version "3.25.0" + resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.25.0.tgz#d51d4ba87a97f6d366b9a3a4bd59461d5c9925b3" + integrity sha512-nvahN6tUCnES9CXCKEzEHkWy7mH39KsQoCk6eehIT3eG1pw/eYUqXFAmmWIL3g2VDCiGavpSf1/BUTnAXE2VsQ== + dependencies: + "@react-aria/breadcrumbs" "^3.5.2" + "@react-aria/button" "^3.7.2" + "@react-aria/calendar" "^3.3.0" + "@react-aria/checkbox" "^3.9.1" + "@react-aria/combobox" "^3.6.1" + "@react-aria/datepicker" "^3.4.1" + "@react-aria/dialog" "^3.5.2" + "@react-aria/dnd" "^3.2.1" + "@react-aria/focus" "^3.12.1" + "@react-aria/gridlist" "^3.4.0" + "@react-aria/i18n" "^3.7.2" + "@react-aria/interactions" "^3.15.1" + "@react-aria/label" "^3.5.2" + "@react-aria/link" "^3.5.1" + "@react-aria/listbox" "^3.9.1" + "@react-aria/menu" "^3.9.1" + "@react-aria/meter" "^3.4.2" + "@react-aria/numberfield" "^3.5.1" + "@react-aria/overlays" "^3.14.1" + "@react-aria/progress" "^3.4.2" + "@react-aria/radio" "^3.6.1" + "@react-aria/searchfield" "^3.5.2" + "@react-aria/select" "^3.10.1" + "@react-aria/selection" "^3.15.0" + "@react-aria/separator" "^3.3.2" + "@react-aria/slider" "^3.4.1" + "@react-aria/ssr" "^3.6.0" + "@react-aria/switch" "^3.5.1" + "@react-aria/table" "^3.9.1" + "@react-aria/tabs" "^3.6.0" + "@react-aria/tag" "^3.0.0" + "@react-aria/textfield" "^3.9.2" + "@react-aria/tooltip" "^3.5.1" + "@react-aria/utils" "^3.17.0" + "@react-aria/visually-hidden" "^3.8.1" + "@react-types/shared" "^3.18.1" + +react-clientside-effect@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" + integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg== dependencies: - "@icons/material" "^0.2.4" - lodash "^4.17.15" - lodash-es "^4.17.15" - material-colors "^1.2.1" - prop-types "^15.5.10" - reactcss "^1.2.0" - tinycolor2 "^1.4.1" + "@babel/runtime" "^7.12.13" react-cool-dimensions@^2.0.7: version "2.0.7" @@ -8331,6 +11426,27 @@ react-draggable@^4.0.0, react-draggable@^4.0.3: clsx "^1.1.1" prop-types "^15.8.1" +react-dropzone@^14.0.0: + version "14.2.3" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.2.3.tgz#0acab68308fda2d54d1273a1e626264e13d4e84b" + integrity sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug== + dependencies: + attr-accept "^2.2.2" + file-selector "^0.6.0" + prop-types "^15.8.1" + +react-focus-lock@^2.9.4: + version "2.9.4" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.9.4.tgz#4753f6dcd167c39050c9d84f9c63c71b3ff8462e" + integrity sha512-7pEdXyMseqm3kVjhdVH18sovparAzLg5h6WvIx7/Ck3ekjhrrDMEegHSa3swwC8wgfdd7DIdUVRGeiHT9/7Sgg== + dependencies: + "@babel/runtime" "^7.0.0" + focus-lock "^0.11.6" + prop-types "^15.6.2" + react-clientside-effect "^1.2.6" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + react-force-graph-2d@^1.23.8: version "1.24.0" resolved "https://registry.yarnpkg.com/react-force-graph-2d/-/react-force-graph-2d-1.24.0.tgz#2e0f4c6609986abfdd178b913b957741fc5f4526" @@ -8340,7 +11456,7 @@ react-force-graph-2d@^1.23.8: prop-types "^15.8" react-kapsule "^2.2" -react-gauge-chart@^0.4.0: +react-gauge-chart@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/react-gauge-chart/-/react-gauge-chart-0.4.1.tgz#e5554b9133c871965858078c144b857514e6b139" integrity sha512-xc1pQ6tF3shRpjyzIGA5EeQcRNfjy5og6Ory5fUe9cWChw8ZadaONMnUIpGHdfUefF+Ffzh6HAZuOX5+AMzOzw== @@ -8358,26 +11474,12 @@ react-grid-layout@^1.3.4: react-draggable "^4.0.0" react-resizable "^3.0.4" -react-hot-loader@^4.13.0: - version "4.13.1" - resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.13.1.tgz#979fd7598e27338b3faffae6ed01c65374dace5e" - integrity sha512-ZlqCfVRqDJmMXTulUGic4lN7Ic1SXgHAFw7y/Jb7t25GBgTR0fYAJ8uY4mrpxjRyWGWmqw77qJQGnYbzCvBU7g== - dependencies: - fast-levenshtein "^2.0.6" - global "^4.3.0" - hoist-non-react-statics "^3.3.0" - loader-utils "^2.0.3" - prop-types "^15.6.1" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.1.0" - source-map "^0.7.3" - react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -"react-is@^16.8.0 || ^17.0.0", react-is@^17.0.2: +react-is@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== @@ -8423,7 +11525,7 @@ react-leaflet@^3.2.5: dependencies: "@react-leaflet/core" "^1.1.1" -react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== @@ -8461,6 +11563,11 @@ react-redux@^7.2.6: prop-types "^15.7.2" react-is "^17.0.2" +react-refresh@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" + integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== + react-resizable@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-3.0.4.tgz#aa20108eff28c52c6fddaa49abfbef8abf5e581b" @@ -8469,12 +11576,51 @@ react-resizable@^3.0.4: prop-types "15.x" react-draggable "^4.0.3" +react-select@5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.0.tgz#82921b38f1fcf1471a0b62304da01f2896cd8ce6" + integrity sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ== + dependencies: + "@babel/runtime" "^7.12.0" + "@emotion/cache" "^11.4.0" + "@emotion/react" "^11.8.1" + "@floating-ui/dom" "^1.0.1" + "@types/react-transition-group" "^4.4.0" + memoize-one "^6.0.0" + prop-types "^15.6.0" + react-transition-group "^4.3.0" + use-isomorphic-layout-effect "^1.1.2" + +react-show-more-text@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/react-show-more-text/-/react-show-more-text-1.6.2.tgz#46821c0ccf5fe5e3a28932bb857393a75607f499" + integrity sha512-Z6tRcnEosHvo07vZw36LxCjqYq4ghgaDI273b5XcayJ1PYbT56OKbaQlPqH7W9LGF5rhUVIhEDBPURuG5eO/Uw== + dependencies: + "@babel/polyfill" "^7.12.1" + prop-types "^15.7.2" + +react-syntax-highlighter@^15.5.0: + version "15.5.0" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz#4b3eccc2325fa2ec8eff1e2d6c18fa4a9e07ab20" + integrity sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg== + dependencies: + "@babel/runtime" "^7.3.1" + highlight.js "^10.4.1" + lowlight "^1.17.0" + prismjs "^1.27.0" + refractor "^3.6.0" + +react-table@^7.7.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.8.0.tgz#07858c01c1718c09f7f1aed7034fcfd7bda907d2" + integrity sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA== + react-testing-library@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/react-testing-library/-/react-testing-library-8.0.1.tgz#b3dd43bce3fa88423cf0a23292fb819023c227cc" integrity sha512-Gq4JC9r3prA4hYwo7afcbHHMFckO29+5Nrh2KblAEPuK/DWaU0bJE1vtpAgLhzhY9bBirmcgjjIHljHEwGAXKw== -react-transition-group@^4.4.0, react-transition-group@^4.4.5: +react-transition-group@^4.3.0, react-transition-group@^4.4.5: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== @@ -8484,11 +11630,36 @@ react-transition-group@^4.4.0, react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" +react-universal-interface@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" + integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== + react-use-error-boundary@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/react-use-error-boundary/-/react-use-error-boundary-3.0.0.tgz#c5b44acf9ab376f59a219d740ac372b05aba6240" integrity sha512-5urkfyU3ZzInEMSHe1gxtDzlQAHs0krTt0V6h8H2L5nXhDKq3OYXnCs9lGHDkEkYvLmsphw8ap5g8uYfvrkJng== +react-use@^17.4.0: + version "17.4.0" + resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.4.0.tgz#cefef258b0a6c534a5c8021c2528ac6e1a4cdc6d" + integrity sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q== + dependencies: + "@types/js-cookie" "^2.2.6" + "@xobotyi/scrollbar-width" "^1.9.5" + copy-to-clipboard "^3.3.1" + fast-deep-equal "^3.1.3" + fast-shallow-equal "^1.0.0" + js-cookie "^2.2.1" + nano-css "^5.3.1" + react-universal-interface "^0.6.2" + resize-observer-polyfill "^1.5.1" + screenfull "^5.1.0" + set-harmonic-interval "^1.0.1" + throttle-debounce "^3.0.1" + ts-easing "^0.2.0" + tslib "^2.1.0" + react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -8497,12 +11668,12 @@ react@^17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" -reactcss@^1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" - integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A== +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== dependencies: - lodash "^4.0.1" + pify "^2.3.0" readable-stream@^2.0.1, readable-stream@^2.3.0, readable-stream@^2.3.5: version "2.3.7" @@ -8547,18 +11718,6 @@ rechoir@^0.7.0: dependencies: resolve "^1.9.0" -recompose@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" - integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w== - dependencies: - "@babel/runtime" "^7.0.0" - change-emitter "^0.1.2" - fbjs "^0.8.1" - hoist-non-react-statics "^2.3.1" - react-lifecycles-compat "^3.0.2" - symbol-observable "^1.0.4" - redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -8584,6 +11743,15 @@ redux@^4.0.0: dependencies: "@babel/runtime" "^7.9.2" +refractor@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" + integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA== + dependencies: + hastscript "^6.0.0" + parse-entities "^2.0.0" + prismjs "~1.27.0" + regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -8601,7 +11769,7 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.11: +regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.4: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== @@ -8646,6 +11814,13 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" +release-zalgo@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" + integrity sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA== + dependencies: + es6-error "^4.0.1" + remark-gfm@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f" @@ -8682,20 +11857,35 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@^4.1.5: - version "4.1.7" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42" - integrity sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A== +reselect@^4.1.6, reselect@^4.1.8: + version "4.1.8" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" + integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== + +resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== resolve-alpn@^1.0.0: version "1.2.1" @@ -8719,7 +11909,7 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.9.0: +resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.9.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -8728,6 +11918,15 @@ resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.9.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.2: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.4: version "2.0.0-next.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" @@ -8784,6 +11983,13 @@ robust-predicates@^3.0.0: resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a" integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g== +rtl-css-js@^1.14.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.16.1.tgz#4b48b4354b0ff917a30488d95100fbf7219a3e80" + integrity sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg== + dependencies: + "@babel/runtime" "^7.1.2" + run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -8882,6 +12088,11 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" +screenfull@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" + integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== + seek-bzip@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" @@ -8911,7 +12122,14 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^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.7: +semver@^7.3.2: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +semver@^7.3.7, semver@^7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== @@ -8977,6 +12195,16 @@ serverless-finch@^4.0.0: mime "^3.0.0" minimatch "^5.0.1" +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-harmonic-interval@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" + integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== + setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -9116,6 +12344,11 @@ source-map-support@^0.5.16, source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA== + source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -9131,11 +12364,33 @@ source-map@^0.7.3: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + space-separated-tokens@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== +spawn-wrap@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" + integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg== + dependencies: + foreground-child "^2.0.0" + is-windows "^1.0.2" + make-dir "^3.0.0" + rimraf "^3.0.0" + signal-exit "^3.0.2" + which "^2.0.1" + spdy-transport@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" @@ -9159,6 +12414,11 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + sprintf-kit@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/sprintf-kit/-/sprintf-kit-2.0.1.tgz#bb837e8fa4b28f094531d8e33669120027236bb8" @@ -9181,6 +12441,13 @@ sshpk@^1.14.1: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stack-generator@^2.0.5: + version "2.0.10" + resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.10.tgz#8ae171e985ed62287d4f1ed55a1633b3fb53bb4d" + integrity sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ== + dependencies: + stackframe "^1.3.4" + stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -9188,6 +12455,28 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== + +stacktrace-gps@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz#0c40b24a9b119b20da4525c398795338966a2fb0" + integrity sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ== + dependencies: + source-map "0.5.6" + stackframe "^1.3.4" + +stacktrace-js@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" + integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== + dependencies: + error-stack-parser "^2.0.6" + stack-generator "^2.0.5" + stacktrace-gps "^3.0.4" + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -9242,7 +12531,7 @@ string.prototype.matchall@^4.0.8: regexp.prototype.flags "^1.4.3" side-channel "^1.0.4" -string.prototype.trimend@^1.0.6: +string.prototype.trimend@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== @@ -9251,7 +12540,7 @@ string.prototype.trimend@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" -string.prototype.trimstart@^1.0.6: +string.prototype.trimstart@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== @@ -9293,6 +12582,11 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + strip-dirs@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" @@ -9346,9 +12640,9 @@ style-loader@^1.1.3: schema-utils "^2.7.0" style-mod@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.0.tgz#97e7c2d68b592975f2ca7a63d0dd6fcacfe35a01" - integrity sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw== + version "4.0.2" + resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.2.tgz#ef9e14c4c67428bcf31cc886787e81ca7f8f5021" + integrity sha512-C4myMmRTO8iaC5Gg+N1ftK2WT4eXUTMAa+HEFPPrfVeO/NtqLTtAmV1HbqnuGtLwCek44Ra76fdGUkSqjiMPcQ== style-to-object@^0.4.0: version "0.4.1" @@ -9373,11 +12667,29 @@ styled-components@^5.3.3: shallowequal "^1.1.0" supports-color "^5.5.0" -stylis@4.1.3: +stylis@4.1.3, stylis@^4.0.6: version "4.1.3" resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== + +sucrase@^3.32.0: + version "3.32.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.32.0.tgz#c4a95e0f1e18b6847127258a75cf360bc568d4a7" + integrity sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "7.1.6" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -9411,10 +12723,39 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -symbol-observable@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +tabbable@^6.0.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.1.1.tgz#40cfead5ed11be49043f04436ef924c8890186a0" + integrity sha512-4kl5w+nCB44EVRdO0g/UGoOp3vlwgycUVtkk/7DPyeLZUCuNFFKCFG6/t/DgHLrUPHjrZg6s5tNm+56Q2B0xyg== + +tailwindcss@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.2.tgz#2f9e35d715fdf0bbf674d90147a0684d7054a2d3" + integrity sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.18.2" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + resolve "^1.22.2" + sucrase "^3.32.0" tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" @@ -9455,11 +12796,39 @@ terser@^5.14.1: commander "^2.20.0" source-map-support "~0.5.20" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +throttle-debounce@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" + integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== + throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" @@ -9488,7 +12857,7 @@ tiny-warning@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tinycolor2@^1.4.1, tinycolor2@^1.6.0: +tinycolor2@^1.4.2, tinycolor2@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== @@ -9524,6 +12893,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== + toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -9567,6 +12941,16 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== +ts-easing@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" + integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + tsconfig-paths@^3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" @@ -9582,11 +12966,16 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +"tslib@^2.4.1 || ^1.9.3": + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -9623,6 +13012,11 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +type-fest@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -9641,14 +13035,12 @@ type@^2.1.0, type@^2.5.0, type@^2.6.0, type@^2.7.2: resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" + is-typedarray "^1.0.0" typescript@^4.8.4: version "4.9.5" @@ -9785,6 +13177,14 @@ update-browserslist-db@^1.0.10: escalade "^3.1.1" picocolors "^1.0.0" +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" @@ -9792,6 +13192,18 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +use-callback-ref@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" + integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w== + dependencies: + tslib "^2.0.0" + +use-isomorphic-layout-effect@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb" + integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA== + use-neo4j@^0.3.13: version "0.3.13" resolved "https://registry.yarnpkg.com/use-neo4j/-/use-neo4j-0.3.13.tgz#3a8188a10ce9be172082443ffb09c25ed7cb4329" @@ -9801,6 +13213,14 @@ use-neo4j@^0.3.13: neo4j-driver "^4.4.5" react-testing-library "^8.0.1" +use-sidecar@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -9967,10 +13387,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.67.0: - version "5.76.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.0.tgz#f9fb9fb8c4a7dbdcd0d56a98e56b8a942ee2692c" - integrity sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA== +webpack@^5.77.0: + version "5.77.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.77.0.tgz#dea3ad16d7ea6b84aa55fa42f4eac9f30e7eb9b4" + integrity sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" @@ -10011,11 +13431,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -whatwg-fetch@>=0.10.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" - integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== - whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -10045,6 +13460,11 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + which-typed-array@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" @@ -10097,6 +13517,16 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + write-file-atomic@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" @@ -10115,6 +13545,11 @@ xtend@^4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" @@ -10130,10 +13565,35 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@^2.1.3, yaml@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4" - integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw== +yaml@^2.1.1, yaml@^2.1.3, yaml@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.2.tgz#ec551ef37326e6d42872dad1970300f8eb83a073" + integrity sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^15.0.2: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" yauzl@^2.10.0, yauzl@^2.4.2: version "2.10.0"