From 4ef4220d40799a81090fcbe46038b7902af97c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Silva?= Date: Thu, 30 Jul 2026 17:46:57 +0000 Subject: [PATCH 01/10] PMM-15028 Flatten dashboards/, move pmm-app into the ui/ monorepo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructures developer experience around Grafana dashboards and the QAN Grafana plugin (pmm-app): - Flatten dashboards/dashboards/* up to dashboards/, so the top-level dashboards/ folder holds only JSON dashboard definitions (plus misc/ tooling and packaging metadata required by the RPM spec). - Move pmm-app from dashboards/pmm-app into ui/apps/pmm-app as a member of the existing ui/ Yarn workspaces + Turborepo monorepo, alongside pmm and pmm-compat. The plugin id/dist layout are unchanged. - Recreate the src/dashboards symlink at its new location, now pointing at the flattened top-level dashboards/ folder — plugin.json's include paths keep working unchanged. - Fix pmm-app's lint/test scripts so they're non-mutating/one-shot (required once folded into a shared workspace pipeline), matching the pmm-compat app's conventions. - Add a chokidar-based watcher (scripts/watch-dashboards.mjs) that mirrors dashboard JSON edits into the provisioned dashboards directory during local dev, so both dashboard JSON and QAN JS/TS changes show up without any manual reload command. Wired into pmm-app's `dev` script and into .devcontainer/Makefile's run-ui/build-ui targets. - Update AGENTS.md guides and CONTRIBUTING docs to match the new layout. Out of scope for this change (flagged as required follow-up, see PR description): .github/workflows/dashboards.yml and ui.yml, and build/packages/rpm/server/SPECS/percona-dashboards.spec still reference the old paths and need a dedicated PR validated with a real CI run and RPM build. --- .devcontainer/Makefile | 26 +--- AGENTS.md | 11 +- dashboards/.editorconfig | 30 +--- dashboards/.gitignore | 14 +- dashboards/AGENTS.md | 59 +++++++ .../Experimental/DB_Cluster_Summary.json | 0 .../Experimental/databases_overview.json | 0 .../Insight/Advanced_Data_Exploration.json | 0 .../Insight/Home_Dashboard.json | 0 .../Insight/Prometheus_Exporter_Status.json | 0 .../Prometheus_Exporters_Overview.json | 0 .../Insight/VictoriaMetrics.json | 0 .../VictoriaMetrics_Agents_Overview.json | 0 .../Databases_on_Kubernetes.json | 0 .../Kubernetes_Cluster_Overview.json | 0 dashboards/Makefile | 52 ------- .../MongoDB/MongoDB_Backup_Details.json | 0 .../MongoDB/MongoDB_Cluster_Summary.json | 0 .../MongoDB/MongoDB_Collections_Overview.json | 0 .../MongoDB/MongoDB_InMemory_Details.json | 0 .../MongoDB/MongoDB_Instance_Summary.json | 0 .../MongoDB/MongoDB_Instances_Compare.json | 0 .../MongoDB/MongoDB_Instances_Overview.json | 0 .../MongoDB/MongoDB_MMAPv1_Details.json | 0 .../MongoDB/MongoDB_Oplog_Details.json | 0 .../MongoDB/MongoDB_ReplSet_Summary.json | 0 .../MongoDB/MongoDB_Router_Summary.json | 0 .../MongoDB/MongoDB_Unused_Indexes.json | 0 .../MongoDB/MongoDB_WiredTiger_Details.json | 0 .../MySQL/HAProxy_Instance_Summary.json | 0 .../MySQL/MySQL_Amazon_Aurora_Details.json | 0 ...ySQL_Command_Handler_Counters_Compare.json | 0 .../MySQL_Group_Replication_Summary.json | 0 .../MySQL_InnoDB_Compression_Details.json | 0 .../MySQL/MySQL_InnoDB_Details.json | 0 .../MySQL/MySQL_Instance_Summary.json | 0 .../MySQL/MySQL_Instances_Compare.json | 0 .../MySQL/MySQL_Instances_Overview.json | 0 .../MySQL/MySQL_MyISAM_Aria_Details.json | 0 .../MySQL/MySQL_MyRocks_Details.json | 0 .../MySQL_Performance_Schema_Details.json | 0 .../MySQL_Query_Response_Time_Details.json | 0 .../MySQL/MySQL_Replication_Summary.json | 0 .../MySQL/MySQL_Table_Details.json | 0 .../MySQL/MySQL_User_Details.json | 0 .../MySQL_Wait_Event_Analyses_Details.json | 0 .../MySQL/PXC_Galera_Cluster_Summary.json | 0 .../MySQL/PXC_Galera_Node_Summary.json | 0 .../MySQL/PXC_Galera_Nodes_Compare.json | 0 .../MySQL/ProxySQL_Instance_Summary.json | 0 .../OS/CPU_Utilization_Details.json | 0 .../{dashboards => }/OS/Disk_Details.json | 0 .../{dashboards => }/OS/Memory_Details.json | 0 .../{dashboards => }/OS/NUMA_Details.json | 0 .../{dashboards => }/OS/Network_Details.json | 0 .../{dashboards => }/OS/Node_Summary.json | 0 .../OS/Node_Temperature_Details.json | 0 .../{dashboards => }/OS/Nodes_Compare.json | 0 .../{dashboards => }/OS/Nodes_Overview.json | 0 .../OS/Processes_Details.json | 0 .../PMM Health/Environments_Overview.json | 0 .../PMM Health/PMM_HA_Health_Overview.json | 0 .../PMM Health/PMM_Health.json | 0 ...tgreSQL_Checkpoints_Buffers_WAL_Usage.json | 0 .../PostgreSQL_Instance_Summary.json | 0 .../PostgreSQL_Instances_Compare.json | 0 .../PostgreSQL_Instances_Overview.json | 0 .../PostgreSQL_Overview_Extended.json | 0 .../PostgreSQL_Patroni_Details.json | 0 .../PostgreSQL_Replication_Overview.json | 0 .../PostgreSQL/PostgreSQL_Top_Queries.json | 0 .../Query Analytics/pmm-qan.json | 0 .../Valkey/Valkey_Clients.json | 0 .../Valkey/Valkey_ClusterDetails.json | 0 .../Valkey/Valkey_CommandDetails.json | 0 .../{dashboards => }/Valkey/Valkey_Load.json | 0 .../Valkey/Valkey_Memory.json | 0 .../Valkey/Valkey_Network.json | 0 .../Valkey/Valkey_Overview.json | 0 .../Valkey/Valkey_PersistenceDetails.json | 0 .../Valkey/Valkey_Replication.json | 0 .../Valkey/Valkey_Slowlog.json | 0 dashboards/dashboards/AGENTS.md | 56 ------- dashboards/pmm-app/AGENTS.md | 146 ------------------ dashboards/pmm-app/src/dashboards | 1 - ui/AGENTS.md | 5 +- .../apps}/pmm-app/.config/.cprc.json | 0 .../apps}/pmm-app/.config/.eslintrc | 0 .../apps}/pmm-app/.config/.prettierrc.js | 0 .../apps}/pmm-app/.config/README.md | 0 .../apps}/pmm-app/.config/jest-setup.js | 0 .../apps}/pmm-app/.config/jest.config.js | 0 .../.config/jest/mocks/react-inlinesvg.tsx | 0 .../apps}/pmm-app/.config/jest/utils.js | 0 .../apps}/pmm-app/.config/tsconfig.json | 0 .../apps}/pmm-app/.config/types/custom.d.ts | 0 .../pmm-app/.config/webpack/constants.ts | 0 .../apps}/pmm-app/.config/webpack/utils.ts | 0 .../pmm-app/.config/webpack/webpack.config.ts | 0 {dashboards => ui/apps}/pmm-app/.eslintrc | 0 ui/apps/pmm-app/.gitignore | 8 + {dashboards => ui/apps}/pmm-app/.nvmrc | 0 .../apps}/pmm-app/.prettierrc.js | 0 ui/apps/pmm-app/AGENTS.md | 143 +++++++++++++++++ {dashboards => ui/apps}/pmm-app/CHANGELOG.md | 0 {dashboards => ui/apps}/pmm-app/CODE-STYLE.md | 0 .../apps/pmm-app}/CONTRIBUTING.md | 0 {dashboards => ui/apps}/pmm-app/LICENSE | 0 {dashboards => ui/apps}/pmm-app/README.md | 0 {dashboards => ui/apps/pmm-app}/codecov.yml | 0 .../apps}/pmm-app/config/jest-setup.ts | 0 .../apps}/pmm-app/docker-compose.yaml | 0 {dashboards => ui/apps}/pmm-app/env.list | 0 {dashboards => ui/apps}/pmm-app/jest-setup.js | 0 .../apps}/pmm-app/jest.config.js | 0 {dashboards => ui/apps}/pmm-app/package.json | 14 +- ui/apps/pmm-app/scripts/watch-dashboards.mjs | 51 ++++++ .../pmm-app/src/__mocks__/react-inlinesvg.tsx | 0 ui/apps/pmm-app/src/dashboards | 1 + .../apps}/pmm-app/src/img/pmm-logo.svg | 0 {dashboards => ui/apps}/pmm-app/src/module.ts | 0 .../apps}/pmm-app/src/plugin.json | 0 .../apps}/pmm-app/src/pmm-qan/module.ts | 0 .../panel/QueryAnalytics.constants.test.tsx | 0 .../pmm-qan/panel/QueryAnalytics.constants.ts | 0 .../pmm-qan/panel/QueryAnalytics.messages.ts | 0 .../pmm-qan/panel/QueryAnalytics.styles.ts | 0 .../panel/QueryAnalytics.tools.test.ts | 0 .../src/pmm-qan/panel/QueryAnalytics.tools.ts | 0 .../src/pmm-qan/panel/QueryAnalytics.tsx | 0 .../components/BarChart/BarChart.styles.ts | 0 .../panel/components/BarChart/BarChart.tsx | 0 .../components/BarChart/BarChart.types.ts | 0 .../components/BarChart/BarChart.utils.ts | 0 .../components/Details/Details.constants.ts | 0 .../panel/components/Details/Details.hooks.ts | 0 .../components/Details/Details.messages.ts | 0 .../components/Details/Details.service.ts | 0 .../components/Details/Details.styles.ts | 0 .../panel/components/Details/Details.tsx | 0 .../panel/components/Details/Details.types.ts | 0 .../Details/Example/Example.test.tsx | 0 .../Details/Example/Example.tools.tsx | 0 .../components/Details/Example/Example.tsx | 0 .../Details/Example/Example.types.ts | 0 .../Example/ParseError/ParseError.messages.ts | 0 .../Example/ParseError/ParseError.test.tsx | 0 .../Details/Example/ParseError/ParseError.tsx | 0 .../Details/Explain/Explain.hooks.ts | 0 .../Details/Explain/Explain.tools.test.ts | 0 .../Details/Explain/Explain.tools.ts | 0 .../components/Details/Explain/Explain.tsx | 0 .../Details/Explain/Explain.types.ts | 0 .../ClassicExplain/ClassicExplain.test.tsx | 0 .../ClassicExplain/ClassicExplain.tsx | 0 .../JsonExplain/JsonExplain.test.tsx | 0 .../components/JsonExplain/JsonExplain.tsx | 0 .../ReplacedQueryMessage.styles.ts | 0 .../ReplacedQueryMessage.tsx | 0 .../VisualExplain/VisualExplain.test.tsx | 0 .../VisualExplain/VisualExplain.tsx | 0 .../ExplainPlaceholders.tsx | 0 .../ExplainPlaceholders.types.ts | 0 .../PlaceholdersForm.messages.ts | 0 .../PlaceholdersForm.styles.ts | 0 .../PlaceholdersForm/PlaceholdersForm.tsx | 0 .../PlaceholdersForm.types.ts | 0 .../PlaceholdersForm.utils.ts | 0 .../PlaceholdersForm/index.ts | 0 .../QueryFingerprint.test.tsx | 0 .../QueryFingerprint/QueryFingerprint.tsx | 0 .../QueryFingerprint.types.ts | 0 .../QueryFingerprint.utils.ts | 0 .../QueryFingerprint/index.ts | 0 .../Details/ExplainPlaceholders/index.ts | 0 .../Details/Metadata/Metadata.constants.ts | 0 .../Details/Metadata/Metadata.styles.ts | 0 .../components/Details/Metadata/Metadata.tsx | 0 .../Details/Metadata/Metadata.types.ts | 0 .../Details/Metadata/Metadata.utils.ts | 0 .../Details/Metrics/Metrics.constants.ts | 0 .../Details/Metrics/Metrics.service.ts | 0 .../Details/Metrics/Metrics.styles.ts | 0 .../Details/Metrics/Metrics.test.tsx | 0 .../components/Details/Metrics/Metrics.tsx | 0 .../Details/Metrics/Metrics.types.ts | 0 .../Details/Metrics/Metrics.utils.test.ts | 0 .../Details/Metrics/Metrics.utils.ts | 0 .../Metrics/__mocks__/histogramStubs.ts | 0 .../Metrics/hooks/__mocks__/useHistogram.ts | 0 .../Details/Metrics/hooks/useHistogram.ts | 0 .../Details/Metrics/hooks/useMetricDetails.ts | 0 .../components/Details/Plan/Plan.hooks.ts | 0 .../components/Details/Plan/Plan.messages.ts | 0 .../components/Details/Plan/Plan.service.ts | 0 .../components/Details/Plan/Plan.styles.ts | 0 .../components/Details/Plan/Plan.test.tsx | 0 .../panel/components/Details/Plan/Plan.tsx | 0 .../components/Details/Plan/Plan.types.ts | 0 .../Details/Plan/__mocks__/Plan.hooks.ts | 0 .../Details/Plan/__mocks__/planStubs.ts | 0 .../Details/Table/TableContainer.constants.ts | 0 .../Details/Table/TableContainer.hooks.ts | 0 .../Details/Table/TableContainer.tools.ts | 0 .../Details/Table/TableContainer.tsx | 0 .../Details/Table/TableContainer.types.ts | 0 .../components/Indexes/Indexes.hooks.tsx | 0 .../Table/components/Indexes/Indexes.tsx | 0 .../Table/components/Status/Status.hooks.tsx | 0 .../Table/components/Status/Status.tsx | 0 .../Details/Table/components/Table.types.ts | 0 .../TableCreate/TableCreate.hooks.tsx | 0 .../components/TableCreate/TableCreate.tsx | 0 .../Details/TopQuery/TopQuery.styles.ts | 0 .../Details/TopQuery/TopQuery.test.tsx | 0 .../components/Details/TopQuery/TopQuery.tsx | 0 .../Details/TopQuery/TopQuery.types.ts | 0 .../Details/database-models/index.ts | 0 .../database-models/mongodb/mongodb.ts | 0 .../database-models/mongodb/service.ts | 0 .../Details/database-models/mysql/mysql.ts | 0 .../database-models/mysql/mysql.types.ts | 0 .../database-models/mysql/mysql.utils.ts | 0 .../Details/database-models/mysql/service.ts | 0 .../database-models/postgresql/postgresql.ts | 0 .../database-models/postgresql/service.ts | 0 .../Details/database-models/utils.test.ts | 0 .../Details/database-models/utils.ts | 0 .../pmm-qan/panel/components/Details/index.ts | 0 .../components/Filters/Filters.constants.ts | 0 .../components/Filters/Filters.messages.ts | 0 .../components/Filters/Filters.service.ts | 0 .../components/Filters/Filters.styles.ts | 0 .../panel/components/Filters/Filters.tools.ts | 0 .../panel/components/Filters/Filters.tsx | 0 .../panel/components/Filters/Filters.types.ts | 0 .../CheckboxGroup/CheckboxGroup.styles.ts | 0 .../CheckboxGroup/CheckboxGroup.test.tsx | 0 .../CheckboxGroup/CheckboxGroup.tsx | 0 .../CheckboxGroup/CheckboxGroup.types.ts | 0 .../Filters/hooks/__mocks__/useFilters.ts | 0 .../components/Filters/hooks/useFilters.ts | 0 .../Filters/hooks/useInitialFilterValues.ts | 0 .../pmm-qan/panel/components/Filters/index.ts | 0 .../ManageColumns/ManageColumns.scss | 0 .../ManageColumns/ManageColumns.styles.ts | 0 .../ManageColumns/ManageColumns.tsx | 0 .../OptionContent/OptionContent.styles.ts | 0 .../OptionContent/OptionContent.test.tsx | 0 .../OptionContent/OptionContent.tsx | 0 .../components/Overview/Overview.constants.ts | 0 .../components/Overview/Overview.hooks.ts | 0 .../components/Overview/Overview.messages.ts | 0 .../panel/components/Overview/Overview.scss | 0 .../components/Overview/Overview.service.ts | 0 .../panel/components/Overview/Overview.tsx | 0 .../components/Overview/Overview.types.ts | 0 .../DefaultColumns/DefaultColumns.styles.ts | 0 .../DefaultColumns/DefaultColumns.tsx | 0 .../Dimension/Dimension.constants.ts | 0 .../components/Dimension/Dimension.scss | 0 .../components/Dimension/Dimension.styles.ts | 0 .../components/Dimension/Dimension.tsx | 0 .../MetricColumns/MetricColumn.styles.ts | 0 .../MetricColumns/MetricColumns.scss | 0 .../MetricColumns/MetricColumns.test.tsx | 0 .../MetricColumns/MetricColumns.tsx | 0 .../components/QanTable/Table.constants.ts | 0 .../components/QanTable/Table.styles.ts | 0 .../Overview/components/QanTable/Table.tsx | 0 .../components/QanTable/Table.types.ts | 0 .../Overview/components/QanTable/index.ts | 0 .../components/Search/Search.styles.ts | 0 .../components/Search/Search.test.tsx | 0 .../Overview/components/Search/Search.tsx | 0 .../components/Search/Search.types.ts | 0 .../panel/components/Overview/index.ts | 0 .../src/pmm-qan/panel/components/index.ts | 0 .../pmm-qan/panel/provider/provider.tools.ts | 0 .../src/pmm-qan/panel/provider/provider.tsx | 0 .../pmm-qan/panel/provider/provider.types.ts | 0 .../apps}/pmm-app/src/pmm-qan/panel/qan.scss | 0 .../apps}/pmm-app/src/pmm-qan/plugin.json | 0 .../shared/assets/fonts/Roboto/LICENSE.txt | 0 .../assets/fonts/Roboto/Roboto-Regular.ttf | Bin .../pmm-app/src/shared/assets/pmm-logo.svg | 0 .../components/Actions/Actions.service.ts | 0 .../components/Actions/Actions.types.ts | 0 .../components/Actions/Actions.utils.ts | 0 .../src/shared/components/Actions/index.ts | 0 .../Elements/Charts/Latency/Latency.styles.ts | 0 .../Elements/Charts/Latency/Latency.tsx | 0 .../Charts/Sparkline/Sparkline.styles.ts | 0 .../Charts/Sparkline/Sparkline.tools.ts | 0 .../Elements/Charts/Sparkline/Sparkline.tsx | 0 .../Charts/Sparkline/Sparkline.types.ts | 0 .../TimeDistribution.constants.ts | 0 .../TimeDistribution.test.tsx | 0 .../TimeDistribution/TimeDistribution.tsx | 0 .../TimeDistribution.test.tsx.snap | 0 .../TotalPercentage/TotalPercentage.scss | 0 .../TotalPercentage/TotalPercentage.tsx | 0 .../components/Elements/Charts/index.ts | 0 .../components/Elements/Icons/Close.tsx | 0 .../components/Elements/Icons/Database.tsx | 0 .../components/Elements/Icons/Filter.tsx | 0 .../components/Elements/Icons/Icons.styles.ts | 0 .../components/Elements/Icons/Icons.types.ts | 0 .../shared/components/Elements/Icons/Info.tsx | 0 .../components/Elements/Icons/Search.tsx | 0 .../components/Elements/Icons/index.tsx | 0 .../LinkTooltip/LinkTooltip.styles.ts | 0 .../Elements/LinkTooltip/LinkTooltip.test.tsx | 0 .../Elements/LinkTooltip/LinkTooltip.tsx | 0 .../components/Elements/Modal/Modal.styles.ts | 0 .../components/Elements/Modal/Modal.test.tsx | 0 .../components/Elements/Modal/Modal.tsx | 0 .../OverflowTooltip/OverflowTooltip.test.tsx | 0 .../OverflowTooltip/OverflowTooptip.tsx | 0 .../OverflowTooltip.test.tsx.snap | 0 .../Elements/Overlay/Overlay.styles.ts | 0 .../Elements/Overlay/Overlay.test.tsx | 0 .../components/Elements/Overlay/Overlay.tsx | 0 .../Elements/Overlay/Overlay.types.ts | 0 .../QueryTooltip/QueryTooltip.styles.ts | 0 .../Elements/QueryTooltip/QueryTooltip.tsx | 0 .../Elements/ReactJSON/ReactJSON.tsx | 0 .../Elements/Scrollbar/Scrollbar.styles.tsx | 0 .../Elements/Scrollbar/Scrollbar.tsx | 0 .../Scrollbar/__mocks__/Scrollbar.tsx | 0 .../components/Elements/Spinner/Spinner.tsx | 0 .../components/Elements/Table/Table.styles.ts | 0 .../components/Elements/Table/Table.test.tsx | 0 .../components/Elements/Table/Table.tsx | 0 .../components/Elements/Table/Table.types.ts | 0 .../shared/components/Elements/Table/index.ts | 0 .../ButtonWithSpinner.styles.ts | 0 .../ButtonWithSpinner.test.tsx | 0 .../ButtonWithSpinner/ButtonWithSpinner.tsx | 0 .../Form/Checkbox/Checkbox.styles.tsx | 0 .../Form/Checkbox/Checkbox.test.tsx | 0 .../components/Form/Checkbox/Checkbox.tsx | 0 .../Form/Checkbox/Checkbox.types.ts | 0 .../__snapshots__/Checkbox.test.tsx.snap | 0 .../Form/FieldAdapters/Checkbox.tsx | 0 .../components/Form/FieldAdapters/Field.tsx | 0 .../FieldAdapters/FieldAdapters.styles.ts | 0 .../Form/FieldAdapters/FieldAdapters.tsx | 0 .../Form/FormElement/FormElement.tsx | 0 .../Form/Radio/RadioButton.styles.ts | 0 .../Form/Radio/RadioButton.test.tsx | 0 .../components/Form/Radio/RadioButton.tsx | 0 .../Form/Radio/RadioButtonGroup.styles.ts | 0 .../Form/Radio/RadioButtonGroup.test.tsx | 0 .../Form/Radio/RadioButtonGroup.tsx | 0 .../src/shared/components/Form/index.ts | 0 .../components/Hightlight/Highlight.styles.ts | 0 .../components/Hightlight/Highlight.test.tsx | 0 .../components/Hightlight/Highlight.tsx | 0 .../components/Hightlight/Highlight.types.ts | 0 .../components/helpers/Helpers.test.tsx | 0 .../src/shared/components/helpers/Helpers.tsx | 0 .../components/helpers/Humanization.test.ts | 0 .../shared/components/helpers/Humanization.ts | 0 .../helpers/__mocks__/notification-manager.ts | 0 .../__snapshots__/Helpers.test.tsx.snap | 0 .../src/shared/components/helpers/api.test.ts | 0 .../src/shared/components/helpers/api.ts | 0 .../shared/components/helpers/getPmmTheme.ts | 0 .../src/shared/components/helpers/index.ts | 0 .../helpers/notification-manager.ts | 0 .../components/helpers/processMetrics.ts | 0 .../components/helpers/promises.test.tsx | 0 .../src/shared/components/helpers/promises.ts | 0 .../helpers/time-parameters-parser.test.ts | 0 .../helpers/time-parameters-parser.ts | 0 .../components/helpers/validator.types.ts | 0 .../components/helpers/validators.test.tsx | 0 .../shared/components/helpers/validators.ts | 0 .../components/hooks/WindowSize.hooks.ts | 0 .../hooks/__mocks__/parameters.hook.ts | 0 .../components/hooks/parameters.hook.ts | 0 .../src/shared/core/Settings.service.ts | 0 .../shared/core/__mocks__/Settings.service.ts | 0 .../src/shared/core/__mocks__/logger.ts | 0 .../pmm-app/src/shared/core/constants.ts | 0 .../apps}/pmm-app/src/shared/core/index.ts | 0 .../apps}/pmm-app/src/shared/core/logger.ts | 0 .../apps}/pmm-app/src/shared/core/theme.ts | 0 .../apps}/pmm-app/src/shared/core/types.ts | 0 .../apps}/pmm-app/src/shared/core/utils.ts | 0 .../src/shared/global-styles/buttons.scss | 0 .../src/shared/global-styles/charts.scss | 0 .../src/shared/global-styles/fonts.css | 0 .../src/shared/global-styles/spinner.scss | 0 .../global-styles/themes/theme-dark.scss | 0 .../global-styles/themes/theme-light.scss | 0 .../src/shared/global-styles/variables.scss | 0 .../apps}/pmm-app/src/shared/style.less | 0 .../apps}/pmm-app/src/shared/styles.scss | 0 {dashboards => ui/apps}/pmm-app/tsconfig.json | 0 {dashboards => ui/apps}/pmm-app/yarn.lock | 0 402 files changed, 286 insertions(+), 331 deletions(-) create mode 100644 dashboards/AGENTS.md rename dashboards/{dashboards => }/Experimental/DB_Cluster_Summary.json (100%) rename dashboards/{dashboards => }/Experimental/databases_overview.json (100%) rename dashboards/{dashboards => }/Insight/Advanced_Data_Exploration.json (100%) rename dashboards/{dashboards => }/Insight/Home_Dashboard.json (100%) rename dashboards/{dashboards => }/Insight/Prometheus_Exporter_Status.json (100%) rename dashboards/{dashboards => }/Insight/Prometheus_Exporters_Overview.json (100%) rename dashboards/{dashboards => }/Insight/VictoriaMetrics.json (100%) rename dashboards/{dashboards => }/Insight/VictoriaMetrics_Agents_Overview.json (100%) rename dashboards/{dashboards => }/Kubernetes (experimental)/Databases_on_Kubernetes.json (100%) rename dashboards/{dashboards => }/Kubernetes (experimental)/Kubernetes_Cluster_Overview.json (100%) delete mode 100644 dashboards/Makefile rename dashboards/{dashboards => }/MongoDB/MongoDB_Backup_Details.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Cluster_Summary.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Collections_Overview.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_InMemory_Details.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Instance_Summary.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Instances_Compare.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Instances_Overview.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_MMAPv1_Details.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Oplog_Details.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_ReplSet_Summary.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Router_Summary.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_Unused_Indexes.json (100%) rename dashboards/{dashboards => }/MongoDB/MongoDB_WiredTiger_Details.json (100%) rename dashboards/{dashboards => }/MySQL/HAProxy_Instance_Summary.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Amazon_Aurora_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Command_Handler_Counters_Compare.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Group_Replication_Summary.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_InnoDB_Compression_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_InnoDB_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Instance_Summary.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Instances_Compare.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Instances_Overview.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_MyISAM_Aria_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_MyRocks_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Performance_Schema_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Query_Response_Time_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Replication_Summary.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Table_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_User_Details.json (100%) rename dashboards/{dashboards => }/MySQL/MySQL_Wait_Event_Analyses_Details.json (100%) rename dashboards/{dashboards => }/MySQL/PXC_Galera_Cluster_Summary.json (100%) rename dashboards/{dashboards => }/MySQL/PXC_Galera_Node_Summary.json (100%) rename dashboards/{dashboards => }/MySQL/PXC_Galera_Nodes_Compare.json (100%) rename dashboards/{dashboards => }/MySQL/ProxySQL_Instance_Summary.json (100%) rename dashboards/{dashboards => }/OS/CPU_Utilization_Details.json (100%) rename dashboards/{dashboards => }/OS/Disk_Details.json (100%) rename dashboards/{dashboards => }/OS/Memory_Details.json (100%) rename dashboards/{dashboards => }/OS/NUMA_Details.json (100%) rename dashboards/{dashboards => }/OS/Network_Details.json (100%) rename dashboards/{dashboards => }/OS/Node_Summary.json (100%) rename dashboards/{dashboards => }/OS/Node_Temperature_Details.json (100%) rename dashboards/{dashboards => }/OS/Nodes_Compare.json (100%) rename dashboards/{dashboards => }/OS/Nodes_Overview.json (100%) rename dashboards/{dashboards => }/OS/Processes_Details.json (100%) rename dashboards/{dashboards => }/PMM Health/Environments_Overview.json (100%) rename dashboards/{dashboards => }/PMM Health/PMM_HA_Health_Overview.json (100%) rename dashboards/{dashboards => }/PMM Health/PMM_Health.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Checkpoints_Buffers_WAL_Usage.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Instance_Summary.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Instances_Compare.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Instances_Overview.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Overview_Extended.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Patroni_Details.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Replication_Overview.json (100%) rename dashboards/{dashboards => }/PostgreSQL/PostgreSQL_Top_Queries.json (100%) rename dashboards/{dashboards => }/Query Analytics/pmm-qan.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_Clients.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_ClusterDetails.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_CommandDetails.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_Load.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_Memory.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_Network.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_Overview.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_PersistenceDetails.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_Replication.json (100%) rename dashboards/{dashboards => }/Valkey/Valkey_Slowlog.json (100%) delete mode 100644 dashboards/dashboards/AGENTS.md delete mode 100644 dashboards/pmm-app/AGENTS.md delete mode 120000 dashboards/pmm-app/src/dashboards rename {dashboards => ui/apps}/pmm-app/.config/.cprc.json (100%) rename {dashboards => ui/apps}/pmm-app/.config/.eslintrc (100%) rename {dashboards => ui/apps}/pmm-app/.config/.prettierrc.js (100%) rename {dashboards => ui/apps}/pmm-app/.config/README.md (100%) rename {dashboards => ui/apps}/pmm-app/.config/jest-setup.js (100%) rename {dashboards => ui/apps}/pmm-app/.config/jest.config.js (100%) rename {dashboards => ui/apps}/pmm-app/.config/jest/mocks/react-inlinesvg.tsx (100%) rename {dashboards => ui/apps}/pmm-app/.config/jest/utils.js (100%) rename {dashboards => ui/apps}/pmm-app/.config/tsconfig.json (100%) rename {dashboards => ui/apps}/pmm-app/.config/types/custom.d.ts (100%) rename {dashboards => ui/apps}/pmm-app/.config/webpack/constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/.config/webpack/utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/.config/webpack/webpack.config.ts (100%) rename {dashboards => ui/apps}/pmm-app/.eslintrc (100%) create mode 100644 ui/apps/pmm-app/.gitignore rename {dashboards => ui/apps}/pmm-app/.nvmrc (100%) rename {dashboards => ui/apps}/pmm-app/.prettierrc.js (100%) create mode 100644 ui/apps/pmm-app/AGENTS.md rename {dashboards => ui/apps}/pmm-app/CHANGELOG.md (100%) rename {dashboards => ui/apps}/pmm-app/CODE-STYLE.md (100%) rename {dashboards => ui/apps/pmm-app}/CONTRIBUTING.md (100%) rename {dashboards => ui/apps}/pmm-app/LICENSE (100%) rename {dashboards => ui/apps}/pmm-app/README.md (100%) rename {dashboards => ui/apps/pmm-app}/codecov.yml (100%) rename {dashboards => ui/apps}/pmm-app/config/jest-setup.ts (100%) rename {dashboards => ui/apps}/pmm-app/docker-compose.yaml (100%) rename {dashboards => ui/apps}/pmm-app/env.list (100%) rename {dashboards => ui/apps}/pmm-app/jest-setup.js (100%) rename {dashboards => ui/apps}/pmm-app/jest.config.js (100%) rename {dashboards => ui/apps}/pmm-app/package.json (90%) create mode 100644 ui/apps/pmm-app/scripts/watch-dashboards.mjs rename {dashboards => ui/apps}/pmm-app/src/__mocks__/react-inlinesvg.tsx (100%) create mode 120000 ui/apps/pmm-app/src/dashboards rename {dashboards => ui/apps}/pmm-app/src/img/pmm-logo.svg (100%) rename {dashboards => ui/apps}/pmm-app/src/module.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/plugin.json (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/module.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/QueryAnalytics.messages.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Details.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Details.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Details.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.messages.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.hooks.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.test.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.messages.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.test.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/__mocks__/histogramStubs.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.messages.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/Plan.hooks.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/planStubs.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.hooks.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.hooks.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Table.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.hooks.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/mongodb.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/postgresql.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.test.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Details/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/Filters.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/Filters.messages.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/Filters.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/Filters.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/Filters.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/hooks/__mocks__/useFilters.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useFilters.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useInitialFilterValues.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Filters/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/Overview.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/Overview.hooks.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/Overview.messages.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/Overview.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/Overview.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/Overview.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/Overview.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumn.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/Overview/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/components/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/provider/provider.tools.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/provider/provider.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/provider/provider.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/panel/qan.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/pmm-qan/plugin.json (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/assets/fonts/Roboto/LICENSE.txt (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/assets/fonts/Roboto/Roboto-Regular.ttf (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/assets/pmm-logo.svg (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Actions/Actions.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Actions/Actions.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Actions/Actions.utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Actions/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tools.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/__snapshots__/TimeDistribution.test.tsx.snap (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Charts/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/Close.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/Database.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/Filter.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/Icons.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/Icons.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/Info.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/Search.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Icons/index.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Modal/Modal.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Modal/Modal.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Modal/Modal.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooltip.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooptip.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/OverflowTooltip/__snapshots__/OverflowTooltip.test.tsx.snap (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Overlay/Overlay.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Overlay/Overlay.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Overlay/Overlay.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Overlay/Overlay.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/ReactJSON/ReactJSON.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.styles.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Scrollbar/__mocks__/Scrollbar.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Spinner/Spinner.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Table/Table.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Table/Table.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Table/Table.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Table/Table.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Elements/Table/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Checkbox/Checkbox.styles.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Checkbox/Checkbox.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Checkbox/Checkbox.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Checkbox/Checkbox.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Checkbox/__snapshots__/Checkbox.test.tsx.snap (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/FieldAdapters/Checkbox.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/FieldAdapters/Field.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/FormElement/FormElement.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Radio/RadioButton.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Radio/RadioButton.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Form/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Hightlight/Highlight.styles.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Hightlight/Highlight.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Hightlight/Highlight.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/Hightlight/Highlight.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/Helpers.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/Helpers.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/Humanization.test.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/Humanization.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/__mocks__/notification-manager.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/api.test.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/api.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/getPmmTheme.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/notification-manager.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/processMetrics.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/promises.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/promises.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/time-parameters-parser.test.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/time-parameters-parser.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/validator.types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/validators.test.tsx (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/helpers/validators.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/hooks/WindowSize.hooks.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/hooks/__mocks__/parameters.hook.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/components/hooks/parameters.hook.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/Settings.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/__mocks__/Settings.service.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/__mocks__/logger.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/constants.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/index.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/logger.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/theme.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/types.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/core/utils.ts (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/global-styles/buttons.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/global-styles/charts.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/global-styles/fonts.css (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/global-styles/spinner.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/global-styles/themes/theme-dark.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/global-styles/themes/theme-light.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/global-styles/variables.scss (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/style.less (100%) rename {dashboards => ui/apps}/pmm-app/src/shared/styles.scss (100%) rename {dashboards => ui/apps}/pmm-app/tsconfig.json (100%) rename {dashboards => ui/apps}/pmm-app/yarn.lock (100%) diff --git a/.devcontainer/Makefile b/.devcontainer/Makefile index 2141bb61e56..e6b70c6ad09 100644 --- a/.devcontainer/Makefile +++ b/.devcontainer/Makefile @@ -64,11 +64,13 @@ run: run-all ## Aliased to "run-all" ui-setup: ## Install UI dependencies cd ui && yarn install -run-ui: ui-setup setup-livereload ## Start vite dev server for UI with HMR +run-ui: ui-setup setup-livereload ## Start vite dev server for UI with HMR, QAN webpack watch and dashboard JSON sync mv /srv/grafana/plugins/pmm-compat-app /srv/grafana/plugins/pmm-compat-app.bak; \ ln -sfn $(CURDIR)/ui/apps/pmm-compat/dist /srv/grafana/plugins/pmm-compat-app; \ + rm -rf /srv/grafana/plugins/pmm-app/dist; \ + ln -sfn $(CURDIR)/ui/apps/pmm-app/dist /srv/grafana/plugins/pmm-app/dist; \ supervisorctl restart grafana; \ - trap 'rm -f /srv/grafana/plugins/pmm-compat-app; mv /srv/grafana/plugins/pmm-compat-app.bak /srv/grafana/plugins/pmm-compat-app; supervisorctl restart grafana' EXIT; \ + trap 'rm -f /srv/grafana/plugins/pmm-compat-app; mv /srv/grafana/plugins/pmm-compat-app.bak /srv/grafana/plugins/pmm-compat-app; rm -f /srv/grafana/plugins/pmm-app/dist; supervisorctl restart grafana' EXIT; \ cd ui && yarn dev build-ui: ui-setup ## Build UI and deploy to system dirs @@ -78,20 +80,9 @@ build-ui: ui-setup ## Build UI and deploy to system dirs rm -rf /usr/share/percona-dashboards/panels/pmm-compat-app /srv/grafana/plugins/pmm-compat-app cp -r ui/apps/pmm-compat/dist /usr/share/percona-dashboards/panels/pmm-compat-app cp -r ui/apps/pmm-compat/dist /srv/grafana/plugins/pmm-compat-app - supervisorctl restart grafana - -run-qan-ui: setup-qan-ui setup-livereload ## Runs QAN UI with webpack livereload - rm -rf /srv/grafana/plugins/pmm-app/dist - ln -sfn $(CURDIR)/dashboards/pmm-app/dist/ /srv/grafana/plugins/pmm-app/dist; - cd dashboards/pmm-app && yarn dev - -build-qan-ui: setup-qan-ui ## Build QAN UI and deploy - cd dashboards/pmm-app && yarn build rm -rf /srv/grafana/plugins/pmm-app/dist - cp -r dashboards/pmm-app/dist /srv/grafana/plugins/pmm-app/dist - -setup-qan-ui: ## Installs QAN UI dependencies - cd dashboards/pmm-app && yarn install + cp -r ui/apps/pmm-app/dist /srv/grafana/plugins/pmm-app/dist + supervisorctl restart grafana setup-livereload: ## Add livereload scripts to grafana index file grep -q "35729/livereload.js" /usr/share/grafana/public/views/index.html || \ @@ -109,11 +100,6 @@ grafana-be-build: cp ./bin/linux/amd64/grafana /usr/sbin/grafana && \ supervisorctl restart grafana -reload-dashboards: - rm -r /usr/share/percona-dashboards/panels/pmm-app/dist/dashboards - cp -r /root/go/src/github.com/percona/pmm/dashboards/dashboards /usr/share/percona-dashboards/panels/pmm-app/dist/dashboards - supervisorctl restart grafana - # TODO https://jira.percona.com/browse/PMM-3484, see maincover_test.go # run-race-cover: install-race ## Run pmm-managed with race detector and collect coverage information. # go test -coverpkg="github.com/percona/pmm/managed/..." \ diff --git a/AGENTS.md b/AGENTS.md index 968ea64680b..b9e6b402c1c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,8 +33,8 @@ Each PMM component has a dedicated guide with architecture, directory structure, | **qan-api2** (query analytics) | [qan-api2/AGENTS.md](qan-api2/AGENTS.md) | `qan-api2/**` | | **vmproxy** (VictoriaMetrics proxy) | [vmproxy/AGENTS.md](vmproxy/AGENTS.md) | `vmproxy/**` | | **UI** (React frontend) | [ui/AGENTS.md](ui/AGENTS.md) | `ui/**` | -| **Dashboards** (Grafana dashboard definitions) | [dashboards/dashboards/AGENTS.md](dashboards/dashboards/AGENTS.md) | `dashboards/dashboards/**` | -| **QAN App** (Grafana plugin & QAN panel) | [dashboards/pmm-app/AGENTS.md](dashboards/pmm-app/AGENTS.md) | `dashboards/pmm-app/**` | +| **Dashboards** (Grafana dashboard definitions) | [dashboards/AGENTS.md](dashboards/AGENTS.md) | `dashboards/**` | +| **QAN App** (Grafana plugin & QAN panel) | [ui/apps/pmm-app/AGENTS.md](ui/apps/pmm-app/AGENTS.md) | `ui/apps/pmm-app/**` | | **API Tests** (integration tests) | [api-tests/AGENTS.md](api-tests/AGENTS.md) | `api-tests/**` | | **Build & Packaging** | [build/AGENTS.md](build/AGENTS.md) | `build/**` | @@ -111,8 +111,8 @@ Relationships: | `/qan-api2` | qan-api2 | Query Analytics API: ClickHouse ingestion and analytics | [qan-api2/AGENTS.md](qan-api2/AGENTS.md) | | `/vmproxy` | vmproxy | VictoriaMetrics reverse proxy with LBAC filtering | [vmproxy/AGENTS.md](vmproxy/AGENTS.md) | | `/ui` | UI | React/TypeScript PMM frontend (Vite, MUI, TanStack Query) | [ui/AGENTS.md](ui/AGENTS.md) | -| `/dashboards/dashboards` | Grafana Dashboards | Grafana dashboard JSON definitions for MySQL, MongoDB, PostgreSQL, OS, and more | [dashboards/dashboards/AGENTS.md](dashboards/dashboards/AGENTS.md) | -| `/dashboards/pmm-app` | QAN App | Grafana application plugin bundling dashboards and the Query Analytics panel | [dashboards/pmm-app/AGENTS.md](dashboards/pmm-app/AGENTS.md) | +| `/dashboards` | Grafana Dashboards | Grafana dashboard JSON definitions for MySQL, MongoDB, PostgreSQL, OS, and more | [dashboards/AGENTS.md](dashboards/AGENTS.md) | +| `/ui/apps/pmm-app` | QAN App | Grafana application plugin bundling dashboards and the Query Analytics panel | [ui/apps/pmm-app/AGENTS.md](ui/apps/pmm-app/AGENTS.md) | | `/api-tests` | API Tests | Integration tests against live PMM Server | [api-tests/AGENTS.md](api-tests/AGENTS.md) | | `/build` | Build & Packaging | Docker, RPM/DEB, Packer, Ansible | [build/AGENTS.md](build/AGENTS.md) | @@ -226,8 +226,7 @@ All long-running daemons expose on `127.0.0.1`: | Target | Purpose | |--------|---------| | `make env-up` | Start development container (PMM Server) | -| `make run-ui` | Inside devcontainer: Vite HMR for the main PMM UI | -| `make run-qan-ui` | Inside devcontainer: webpack + livereload for the QAN Grafana plugin | +| `make run-ui` | Inside devcontainer: Vite HMR for the main PMM UI, plus webpack + livereload and dashboard JSON sync for the QAN Grafana plugin | | `make gen` | Generate all code (protobuf, reform, mocks, format) | | `make check` | Run linters (buf, golangci-lint, go-sumtype) | | `make format` | Format code (gofumpt, goimports, gci) | diff --git a/dashboards/.editorconfig b/dashboards/.editorconfig index cf5e3c8c48c..96446a83733 100644 --- a/dashboards/.editorconfig +++ b/dashboards/.editorconfig @@ -8,36 +8,8 @@ root = true end_of_line = lf insert_final_newline = true -# Matches multiple files with brace expansion notation -# Set default charset -[*.{js,ts,tsx,py}] +[*.json] charset = utf-8 - -# 4 space indentation -[*.py] -indent_style = space -indent_size = 4 - -[Makefile] -indent_style = tab -indent_size = 4 - -# Indentation override for all JS, TS under pmm-app directory -[pmm-app/src/**.{js,ts,tsx}] -indent_style = space -indent_size = 2 -trim_trailing_whitespace = true - -[pmm-app/tests/**.js] -indent_style = space -indent_size = 2 -trim_trailing_whitespace = true - -[dashboards/*.json] indent_style = space indent_size = 4 trim_trailing_whitespace = true - -[{package.json,docker-compose.yml}] -indent_style = space -indent_size = 2 diff --git a/dashboards/.gitignore b/dashboards/.gitignore index 7aed30871dd..9b76a95ba17 100644 --- a/dashboards/.gitignore +++ b/dashboards/.gitignore @@ -2,19 +2,7 @@ .vscode .DS_Store -# development -.env/ -node_modules -docker-compose.*.y*ml - # PMM-specific -dashboards/PMM_Demo.json +PMM_Demo.json /export-dash.py /import-dash.py -pmm-app.tar.gz -pmm-app/dist/ -pmm-app/coverage/ -pmm-app/video/ -pmm-app/pr.browsers.json -pmm-app/tests/output/ -srv diff --git a/dashboards/AGENTS.md b/dashboards/AGENTS.md new file mode 100644 index 00000000000..166e3816aae --- /dev/null +++ b/dashboards/AGENTS.md @@ -0,0 +1,59 @@ +# Grafana Dashboards Development Guidelines + +> **Parent guide**: [AGENTS.md](../AGENTS.md) — product overview, architecture, domain model, global conventions +> **Related**: [ui/apps/pmm-app/AGENTS.md](../ui/apps/pmm-app/AGENTS.md) (Grafana plugin that bundles these dashboards) · [managed/AGENTS.md](../managed/AGENTS.md) (server backend providing metrics data) + +The `dashboards/` directory contains Grafana dashboard JSON definitions organized by database and domain area, and nothing else besides `misc/` tooling and packaging metadata (`LICENSE`, `README.md`). These are the canonical source for all PMM monitoring dashboards. The `dashboards/misc/` directory provides Python helper scripts for importing, exporting, and converting dashboard JSON files. + +## Architecture + +Dashboard JSON files are standard Grafana dashboard exports. They are loaded into Grafana through two mechanisms: + +1. **Plugin bundling** — `ui/apps/pmm-app/src/plugin.json` declares each dashboard in its `includes` array. `ui/apps/pmm-app/src/dashboards` is a symlink to this top-level `dashboards/` folder; the build copies the referenced JSON files into the plugin `dist/` directory, and Grafana provisions them when the pmm-app plugin is loaded. +2. **Grafana provisioning** — the PMM Server Ansible role configures Grafana to load dashboards from the plugin's `dist/dashboards/` path. + +``` +dashboards/*.json + → ui/apps/pmm-app/src/dashboards (symlink) → pmm-app build (copied to dist/dashboards/) + → Grafana provisioning on PMM Server + → Grafana UI (visualization) +``` + +In local development, `ui/apps/pmm-app`'s `yarn dev` also runs a chokidar watcher (`scripts/watch-dashboards.mjs`) that mirrors any dashboard JSON change straight into the devcontainer's provisioned dashboards path — Grafana's file provisioner polls that path every 60s, so edits show up without restarting anything or running a manual reload command. + +## Dashboard categories + +| Directory | Domain | +|-----------|--------| +| `MySQL/` | MySQL, PXC/Galera, Aurora, ProxySQL, HAProxy | +| `MongoDB/` | MongoDB, WiredTiger, MMAPv1, InMemory, PBM, ReplSet | +| `PostgreSQL/` | PostgreSQL, Patroni | +| `OS/` | Node, CPU, memory, disk, network, NUMA, processes | +| `Valkey/` | Valkey/Redis clients, cluster, memory, replication, slowlog | +| `Insight/` | Home Dashboard, Advanced Data Exploration, VictoriaMetrics, Exporters | +| `Experimental/` | Databases Overview, DB Cluster Summary | +| `PMM Health/` | Environments Overview, PMM Health Overview, HA Health Overview | +| `Query Analytics/` | QAN panel wrapper (`pmm-qan.json`) | +| `Kubernetes (experimental)/` | Kubernetes operator monitoring | + +## Patterns and Conventions + +### Do +- Design dashboards in the Grafana UI, then export the JSON +- Use `misc/cleanup-dash.py` to normalize exported JSON before committing +- Follow the existing directory structure when adding dashboards for a new domain +- Keep one dashboard per JSON file, named to match the dashboard title +- Register new dashboards in `ui/apps/pmm-app/src/plugin.json` under the `includes` array + +### Don't +- Don't edit dashboard JSON by hand unless making targeted fixes — use the Grafana UI for design work +- Don't duplicate dashboard JSON inside `ui/apps/pmm-app/src/` — the canonical source is this top-level `dashboards/` folder +- Don't commit Grafana-generated volatile fields (e.g., `version`, `iteration`) — use `cleanup-dash.py` to strip them +- Don't add non-JSON files at the root of this folder beyond the existing `misc/`, `LICENSE`, and `README.md` — this folder is meant to stay JSON-only otherwise + +## Key Files to Reference + +- `dashboards/` — all dashboard JSON definitions, organized by domain +- `ui/apps/pmm-app/src/plugin.json` — plugin manifest that registers dashboards in Grafana +- `dashboards/README.md` — featured dashboards list +- `ui/apps/pmm-app/CONTRIBUTING.md` — contribution workflow and local dev setup diff --git a/dashboards/dashboards/Experimental/DB_Cluster_Summary.json b/dashboards/Experimental/DB_Cluster_Summary.json similarity index 100% rename from dashboards/dashboards/Experimental/DB_Cluster_Summary.json rename to dashboards/Experimental/DB_Cluster_Summary.json diff --git a/dashboards/dashboards/Experimental/databases_overview.json b/dashboards/Experimental/databases_overview.json similarity index 100% rename from dashboards/dashboards/Experimental/databases_overview.json rename to dashboards/Experimental/databases_overview.json diff --git a/dashboards/dashboards/Insight/Advanced_Data_Exploration.json b/dashboards/Insight/Advanced_Data_Exploration.json similarity index 100% rename from dashboards/dashboards/Insight/Advanced_Data_Exploration.json rename to dashboards/Insight/Advanced_Data_Exploration.json diff --git a/dashboards/dashboards/Insight/Home_Dashboard.json b/dashboards/Insight/Home_Dashboard.json similarity index 100% rename from dashboards/dashboards/Insight/Home_Dashboard.json rename to dashboards/Insight/Home_Dashboard.json diff --git a/dashboards/dashboards/Insight/Prometheus_Exporter_Status.json b/dashboards/Insight/Prometheus_Exporter_Status.json similarity index 100% rename from dashboards/dashboards/Insight/Prometheus_Exporter_Status.json rename to dashboards/Insight/Prometheus_Exporter_Status.json diff --git a/dashboards/dashboards/Insight/Prometheus_Exporters_Overview.json b/dashboards/Insight/Prometheus_Exporters_Overview.json similarity index 100% rename from dashboards/dashboards/Insight/Prometheus_Exporters_Overview.json rename to dashboards/Insight/Prometheus_Exporters_Overview.json diff --git a/dashboards/dashboards/Insight/VictoriaMetrics.json b/dashboards/Insight/VictoriaMetrics.json similarity index 100% rename from dashboards/dashboards/Insight/VictoriaMetrics.json rename to dashboards/Insight/VictoriaMetrics.json diff --git a/dashboards/dashboards/Insight/VictoriaMetrics_Agents_Overview.json b/dashboards/Insight/VictoriaMetrics_Agents_Overview.json similarity index 100% rename from dashboards/dashboards/Insight/VictoriaMetrics_Agents_Overview.json rename to dashboards/Insight/VictoriaMetrics_Agents_Overview.json diff --git a/dashboards/dashboards/Kubernetes (experimental)/Databases_on_Kubernetes.json b/dashboards/Kubernetes (experimental)/Databases_on_Kubernetes.json similarity index 100% rename from dashboards/dashboards/Kubernetes (experimental)/Databases_on_Kubernetes.json rename to dashboards/Kubernetes (experimental)/Databases_on_Kubernetes.json diff --git a/dashboards/dashboards/Kubernetes (experimental)/Kubernetes_Cluster_Overview.json b/dashboards/Kubernetes (experimental)/Kubernetes_Cluster_Overview.json similarity index 100% rename from dashboards/dashboards/Kubernetes (experimental)/Kubernetes_Cluster_Overview.json rename to dashboards/Kubernetes (experimental)/Kubernetes_Cluster_Overview.json diff --git a/dashboards/Makefile b/dashboards/Makefile deleted file mode 100644 index ae5a3c43339..00000000000 --- a/dashboards/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -export IMPORT_DASH_HOST = http://127.0.0.1:3000 -export IMPORT_DASH_USERNAME = admin -export IMPORT_DASH_PASSWORD = admin - -CLICKHOUSE_DATASOURCE_VERSION ?= 4.14.1 -POLYSTAT_PANEL_VERSION ?= 2.1.16 - -release: install build - -install: - cd pmm-app \ - && npm version \ - && yarn install --frozen-lockfile \ - -build: - cd pmm-app \ - && yarn run build - -test: release - cd pmm-app \ - && yarn test:ci - -clean: - rm -r pmm-app/dist/ - -docker_clean: - docker compose stop \ - && docker compose rm -f -v \ - && docker system prune --volumes -f - -install-plugins: - @echo "Installing PMM plugins..." - @echo "To override the platform, set the PLATFORM environment variable." - @echo "Example: PLATFORM=linux/arm64 make upgrade_plugins" - @echo "Installing grafana-clickhouse-datasource plugin..." - @docker run \ - --rm \ - --name grafana \ - --platform="$${PLATFORM:-linux/amd64}" \ - --entrypoint=/bin/bash \ - -v "./panels":/var/lib/grafana/plugins \ - grafana/grafana:11.6 \ - -c "grafana cli --pluginUrl=https://github.com/grafana/clickhouse-datasource/releases/download/v$(CLICKHOUSE_DATASOURCE_VERSION)/grafana-clickhouse-datasource-$(CLICKHOUSE_DATASOURCE_VERSION).linux_amd64.zip plugins install grafana-clickhouse-datasource" - @echo "Installing grafana-polystat-panel plugin..." - @docker run \ - --rm \ - --name grafana \ - --platform="$${PLATFORM:-linux/amd64}" \ - --entrypoint=/bin/bash \ - -v "./panels":/var/lib/grafana/plugins \ - grafana/grafana:11.6 \ - -c "grafana cli --pluginUrl=https://github.com/grafana/grafana-polystat-panel/releases/download/v$(POLYSTAT_PANEL_VERSION)/grafana-polystat-panel-$(POLYSTAT_PANEL_VERSION).zip plugins install grafana-polystat-panel" diff --git a/dashboards/dashboards/MongoDB/MongoDB_Backup_Details.json b/dashboards/MongoDB/MongoDB_Backup_Details.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Backup_Details.json rename to dashboards/MongoDB/MongoDB_Backup_Details.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Cluster_Summary.json b/dashboards/MongoDB/MongoDB_Cluster_Summary.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Cluster_Summary.json rename to dashboards/MongoDB/MongoDB_Cluster_Summary.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Collections_Overview.json b/dashboards/MongoDB/MongoDB_Collections_Overview.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Collections_Overview.json rename to dashboards/MongoDB/MongoDB_Collections_Overview.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_InMemory_Details.json b/dashboards/MongoDB/MongoDB_InMemory_Details.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_InMemory_Details.json rename to dashboards/MongoDB/MongoDB_InMemory_Details.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Instance_Summary.json b/dashboards/MongoDB/MongoDB_Instance_Summary.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Instance_Summary.json rename to dashboards/MongoDB/MongoDB_Instance_Summary.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Instances_Compare.json b/dashboards/MongoDB/MongoDB_Instances_Compare.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Instances_Compare.json rename to dashboards/MongoDB/MongoDB_Instances_Compare.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Instances_Overview.json b/dashboards/MongoDB/MongoDB_Instances_Overview.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Instances_Overview.json rename to dashboards/MongoDB/MongoDB_Instances_Overview.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_MMAPv1_Details.json b/dashboards/MongoDB/MongoDB_MMAPv1_Details.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_MMAPv1_Details.json rename to dashboards/MongoDB/MongoDB_MMAPv1_Details.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Oplog_Details.json b/dashboards/MongoDB/MongoDB_Oplog_Details.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Oplog_Details.json rename to dashboards/MongoDB/MongoDB_Oplog_Details.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_ReplSet_Summary.json b/dashboards/MongoDB/MongoDB_ReplSet_Summary.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_ReplSet_Summary.json rename to dashboards/MongoDB/MongoDB_ReplSet_Summary.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Router_Summary.json b/dashboards/MongoDB/MongoDB_Router_Summary.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Router_Summary.json rename to dashboards/MongoDB/MongoDB_Router_Summary.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_Unused_Indexes.json b/dashboards/MongoDB/MongoDB_Unused_Indexes.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_Unused_Indexes.json rename to dashboards/MongoDB/MongoDB_Unused_Indexes.json diff --git a/dashboards/dashboards/MongoDB/MongoDB_WiredTiger_Details.json b/dashboards/MongoDB/MongoDB_WiredTiger_Details.json similarity index 100% rename from dashboards/dashboards/MongoDB/MongoDB_WiredTiger_Details.json rename to dashboards/MongoDB/MongoDB_WiredTiger_Details.json diff --git a/dashboards/dashboards/MySQL/HAProxy_Instance_Summary.json b/dashboards/MySQL/HAProxy_Instance_Summary.json similarity index 100% rename from dashboards/dashboards/MySQL/HAProxy_Instance_Summary.json rename to dashboards/MySQL/HAProxy_Instance_Summary.json diff --git a/dashboards/dashboards/MySQL/MySQL_Amazon_Aurora_Details.json b/dashboards/MySQL/MySQL_Amazon_Aurora_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Amazon_Aurora_Details.json rename to dashboards/MySQL/MySQL_Amazon_Aurora_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_Command_Handler_Counters_Compare.json b/dashboards/MySQL/MySQL_Command_Handler_Counters_Compare.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Command_Handler_Counters_Compare.json rename to dashboards/MySQL/MySQL_Command_Handler_Counters_Compare.json diff --git a/dashboards/dashboards/MySQL/MySQL_Group_Replication_Summary.json b/dashboards/MySQL/MySQL_Group_Replication_Summary.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Group_Replication_Summary.json rename to dashboards/MySQL/MySQL_Group_Replication_Summary.json diff --git a/dashboards/dashboards/MySQL/MySQL_InnoDB_Compression_Details.json b/dashboards/MySQL/MySQL_InnoDB_Compression_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_InnoDB_Compression_Details.json rename to dashboards/MySQL/MySQL_InnoDB_Compression_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_InnoDB_Details.json b/dashboards/MySQL/MySQL_InnoDB_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_InnoDB_Details.json rename to dashboards/MySQL/MySQL_InnoDB_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_Instance_Summary.json b/dashboards/MySQL/MySQL_Instance_Summary.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Instance_Summary.json rename to dashboards/MySQL/MySQL_Instance_Summary.json diff --git a/dashboards/dashboards/MySQL/MySQL_Instances_Compare.json b/dashboards/MySQL/MySQL_Instances_Compare.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Instances_Compare.json rename to dashboards/MySQL/MySQL_Instances_Compare.json diff --git a/dashboards/dashboards/MySQL/MySQL_Instances_Overview.json b/dashboards/MySQL/MySQL_Instances_Overview.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Instances_Overview.json rename to dashboards/MySQL/MySQL_Instances_Overview.json diff --git a/dashboards/dashboards/MySQL/MySQL_MyISAM_Aria_Details.json b/dashboards/MySQL/MySQL_MyISAM_Aria_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_MyISAM_Aria_Details.json rename to dashboards/MySQL/MySQL_MyISAM_Aria_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_MyRocks_Details.json b/dashboards/MySQL/MySQL_MyRocks_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_MyRocks_Details.json rename to dashboards/MySQL/MySQL_MyRocks_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_Performance_Schema_Details.json b/dashboards/MySQL/MySQL_Performance_Schema_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Performance_Schema_Details.json rename to dashboards/MySQL/MySQL_Performance_Schema_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_Query_Response_Time_Details.json b/dashboards/MySQL/MySQL_Query_Response_Time_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Query_Response_Time_Details.json rename to dashboards/MySQL/MySQL_Query_Response_Time_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_Replication_Summary.json b/dashboards/MySQL/MySQL_Replication_Summary.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Replication_Summary.json rename to dashboards/MySQL/MySQL_Replication_Summary.json diff --git a/dashboards/dashboards/MySQL/MySQL_Table_Details.json b/dashboards/MySQL/MySQL_Table_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Table_Details.json rename to dashboards/MySQL/MySQL_Table_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_User_Details.json b/dashboards/MySQL/MySQL_User_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_User_Details.json rename to dashboards/MySQL/MySQL_User_Details.json diff --git a/dashboards/dashboards/MySQL/MySQL_Wait_Event_Analyses_Details.json b/dashboards/MySQL/MySQL_Wait_Event_Analyses_Details.json similarity index 100% rename from dashboards/dashboards/MySQL/MySQL_Wait_Event_Analyses_Details.json rename to dashboards/MySQL/MySQL_Wait_Event_Analyses_Details.json diff --git a/dashboards/dashboards/MySQL/PXC_Galera_Cluster_Summary.json b/dashboards/MySQL/PXC_Galera_Cluster_Summary.json similarity index 100% rename from dashboards/dashboards/MySQL/PXC_Galera_Cluster_Summary.json rename to dashboards/MySQL/PXC_Galera_Cluster_Summary.json diff --git a/dashboards/dashboards/MySQL/PXC_Galera_Node_Summary.json b/dashboards/MySQL/PXC_Galera_Node_Summary.json similarity index 100% rename from dashboards/dashboards/MySQL/PXC_Galera_Node_Summary.json rename to dashboards/MySQL/PXC_Galera_Node_Summary.json diff --git a/dashboards/dashboards/MySQL/PXC_Galera_Nodes_Compare.json b/dashboards/MySQL/PXC_Galera_Nodes_Compare.json similarity index 100% rename from dashboards/dashboards/MySQL/PXC_Galera_Nodes_Compare.json rename to dashboards/MySQL/PXC_Galera_Nodes_Compare.json diff --git a/dashboards/dashboards/MySQL/ProxySQL_Instance_Summary.json b/dashboards/MySQL/ProxySQL_Instance_Summary.json similarity index 100% rename from dashboards/dashboards/MySQL/ProxySQL_Instance_Summary.json rename to dashboards/MySQL/ProxySQL_Instance_Summary.json diff --git a/dashboards/dashboards/OS/CPU_Utilization_Details.json b/dashboards/OS/CPU_Utilization_Details.json similarity index 100% rename from dashboards/dashboards/OS/CPU_Utilization_Details.json rename to dashboards/OS/CPU_Utilization_Details.json diff --git a/dashboards/dashboards/OS/Disk_Details.json b/dashboards/OS/Disk_Details.json similarity index 100% rename from dashboards/dashboards/OS/Disk_Details.json rename to dashboards/OS/Disk_Details.json diff --git a/dashboards/dashboards/OS/Memory_Details.json b/dashboards/OS/Memory_Details.json similarity index 100% rename from dashboards/dashboards/OS/Memory_Details.json rename to dashboards/OS/Memory_Details.json diff --git a/dashboards/dashboards/OS/NUMA_Details.json b/dashboards/OS/NUMA_Details.json similarity index 100% rename from dashboards/dashboards/OS/NUMA_Details.json rename to dashboards/OS/NUMA_Details.json diff --git a/dashboards/dashboards/OS/Network_Details.json b/dashboards/OS/Network_Details.json similarity index 100% rename from dashboards/dashboards/OS/Network_Details.json rename to dashboards/OS/Network_Details.json diff --git a/dashboards/dashboards/OS/Node_Summary.json b/dashboards/OS/Node_Summary.json similarity index 100% rename from dashboards/dashboards/OS/Node_Summary.json rename to dashboards/OS/Node_Summary.json diff --git a/dashboards/dashboards/OS/Node_Temperature_Details.json b/dashboards/OS/Node_Temperature_Details.json similarity index 100% rename from dashboards/dashboards/OS/Node_Temperature_Details.json rename to dashboards/OS/Node_Temperature_Details.json diff --git a/dashboards/dashboards/OS/Nodes_Compare.json b/dashboards/OS/Nodes_Compare.json similarity index 100% rename from dashboards/dashboards/OS/Nodes_Compare.json rename to dashboards/OS/Nodes_Compare.json diff --git a/dashboards/dashboards/OS/Nodes_Overview.json b/dashboards/OS/Nodes_Overview.json similarity index 100% rename from dashboards/dashboards/OS/Nodes_Overview.json rename to dashboards/OS/Nodes_Overview.json diff --git a/dashboards/dashboards/OS/Processes_Details.json b/dashboards/OS/Processes_Details.json similarity index 100% rename from dashboards/dashboards/OS/Processes_Details.json rename to dashboards/OS/Processes_Details.json diff --git a/dashboards/dashboards/PMM Health/Environments_Overview.json b/dashboards/PMM Health/Environments_Overview.json similarity index 100% rename from dashboards/dashboards/PMM Health/Environments_Overview.json rename to dashboards/PMM Health/Environments_Overview.json diff --git a/dashboards/dashboards/PMM Health/PMM_HA_Health_Overview.json b/dashboards/PMM Health/PMM_HA_Health_Overview.json similarity index 100% rename from dashboards/dashboards/PMM Health/PMM_HA_Health_Overview.json rename to dashboards/PMM Health/PMM_HA_Health_Overview.json diff --git a/dashboards/dashboards/PMM Health/PMM_Health.json b/dashboards/PMM Health/PMM_Health.json similarity index 100% rename from dashboards/dashboards/PMM Health/PMM_Health.json rename to dashboards/PMM Health/PMM_Health.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Checkpoints_Buffers_WAL_Usage.json b/dashboards/PostgreSQL/PostgreSQL_Checkpoints_Buffers_WAL_Usage.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Checkpoints_Buffers_WAL_Usage.json rename to dashboards/PostgreSQL/PostgreSQL_Checkpoints_Buffers_WAL_Usage.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Instance_Summary.json b/dashboards/PostgreSQL/PostgreSQL_Instance_Summary.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Instance_Summary.json rename to dashboards/PostgreSQL/PostgreSQL_Instance_Summary.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Instances_Compare.json b/dashboards/PostgreSQL/PostgreSQL_Instances_Compare.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Instances_Compare.json rename to dashboards/PostgreSQL/PostgreSQL_Instances_Compare.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Instances_Overview.json b/dashboards/PostgreSQL/PostgreSQL_Instances_Overview.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Instances_Overview.json rename to dashboards/PostgreSQL/PostgreSQL_Instances_Overview.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Overview_Extended.json b/dashboards/PostgreSQL/PostgreSQL_Overview_Extended.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Overview_Extended.json rename to dashboards/PostgreSQL/PostgreSQL_Overview_Extended.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Patroni_Details.json b/dashboards/PostgreSQL/PostgreSQL_Patroni_Details.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Patroni_Details.json rename to dashboards/PostgreSQL/PostgreSQL_Patroni_Details.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Replication_Overview.json b/dashboards/PostgreSQL/PostgreSQL_Replication_Overview.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Replication_Overview.json rename to dashboards/PostgreSQL/PostgreSQL_Replication_Overview.json diff --git a/dashboards/dashboards/PostgreSQL/PostgreSQL_Top_Queries.json b/dashboards/PostgreSQL/PostgreSQL_Top_Queries.json similarity index 100% rename from dashboards/dashboards/PostgreSQL/PostgreSQL_Top_Queries.json rename to dashboards/PostgreSQL/PostgreSQL_Top_Queries.json diff --git a/dashboards/dashboards/Query Analytics/pmm-qan.json b/dashboards/Query Analytics/pmm-qan.json similarity index 100% rename from dashboards/dashboards/Query Analytics/pmm-qan.json rename to dashboards/Query Analytics/pmm-qan.json diff --git a/dashboards/dashboards/Valkey/Valkey_Clients.json b/dashboards/Valkey/Valkey_Clients.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_Clients.json rename to dashboards/Valkey/Valkey_Clients.json diff --git a/dashboards/dashboards/Valkey/Valkey_ClusterDetails.json b/dashboards/Valkey/Valkey_ClusterDetails.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_ClusterDetails.json rename to dashboards/Valkey/Valkey_ClusterDetails.json diff --git a/dashboards/dashboards/Valkey/Valkey_CommandDetails.json b/dashboards/Valkey/Valkey_CommandDetails.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_CommandDetails.json rename to dashboards/Valkey/Valkey_CommandDetails.json diff --git a/dashboards/dashboards/Valkey/Valkey_Load.json b/dashboards/Valkey/Valkey_Load.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_Load.json rename to dashboards/Valkey/Valkey_Load.json diff --git a/dashboards/dashboards/Valkey/Valkey_Memory.json b/dashboards/Valkey/Valkey_Memory.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_Memory.json rename to dashboards/Valkey/Valkey_Memory.json diff --git a/dashboards/dashboards/Valkey/Valkey_Network.json b/dashboards/Valkey/Valkey_Network.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_Network.json rename to dashboards/Valkey/Valkey_Network.json diff --git a/dashboards/dashboards/Valkey/Valkey_Overview.json b/dashboards/Valkey/Valkey_Overview.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_Overview.json rename to dashboards/Valkey/Valkey_Overview.json diff --git a/dashboards/dashboards/Valkey/Valkey_PersistenceDetails.json b/dashboards/Valkey/Valkey_PersistenceDetails.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_PersistenceDetails.json rename to dashboards/Valkey/Valkey_PersistenceDetails.json diff --git a/dashboards/dashboards/Valkey/Valkey_Replication.json b/dashboards/Valkey/Valkey_Replication.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_Replication.json rename to dashboards/Valkey/Valkey_Replication.json diff --git a/dashboards/dashboards/Valkey/Valkey_Slowlog.json b/dashboards/Valkey/Valkey_Slowlog.json similarity index 100% rename from dashboards/dashboards/Valkey/Valkey_Slowlog.json rename to dashboards/Valkey/Valkey_Slowlog.json diff --git a/dashboards/dashboards/AGENTS.md b/dashboards/dashboards/AGENTS.md deleted file mode 100644 index 201725de8ec..00000000000 --- a/dashboards/dashboards/AGENTS.md +++ /dev/null @@ -1,56 +0,0 @@ -# Grafana Dashboards Development Guidelines - -> **Parent guide**: [AGENTS.md](../../AGENTS.md) — product overview, architecture, domain model, global conventions -> **Related**: [dashboards/pmm-app/AGENTS.md](../pmm-app/AGENTS.md) (Grafana plugin that bundles these dashboards) · [managed/AGENTS.md](../../managed/AGENTS.md) (server backend providing metrics data) - -The `dashboards/dashboards/` directory contains Grafana dashboard JSON definitions organized by database and domain area. These are the canonical source for all PMM monitoring dashboards. The `dashboards/misc/` directory provides Python helper scripts for importing, exporting, and converting dashboard JSON files. - -## Architecture - -Dashboard JSON files are standard Grafana dashboard exports. They are loaded into Grafana through two mechanisms: - -1. **Plugin bundling** — `pmm-app/src/plugin.json` declares each dashboard in its `includes` array. The build copies them into the plugin `dist/` directory, and Grafana provisions them when the pmm-app plugin is loaded. -2. **Grafana provisioning** — the PMM Server Ansible role configures Grafana to load dashboards from the plugin's `dist/dashboards/` path. - -``` -dashboards/dashboards/*.json - → pmm-app build (copied to dist/dashboards/) - → Grafana provisioning on PMM Server - → Grafana UI (visualization) -``` - -## Dashboard categories - -| Directory | Domain | -|-----------|--------| -| `MySQL/` | MySQL, PXC/Galera, Aurora, ProxySQL, HAProxy | -| `MongoDB/` | MongoDB, WiredTiger, MMAPv1, InMemory, PBM, ReplSet | -| `PostgreSQL/` | PostgreSQL, Patroni | -| `OS/` | Node, CPU, memory, disk, network, NUMA, processes | -| `Valkey/` | Valkey/Redis clients, cluster, memory, replication, slowlog | -| `Insight/` | Home Dashboard, Advanced Data Exploration, VictoriaMetrics, Exporters | -| `Experimental/` | Databases Overview, DB Cluster Summary | -| `PMM Health/` | Environments Overview, PMM Health Overview, HA Health Overview | -| `Query Analytics/` | QAN panel wrapper (`pmm-qan.json`) | -| `Kubernetes (experimental)/` | Kubernetes operator monitoring | - -## Patterns and Conventions - -### Do -- Design dashboards in the Grafana UI, then export the JSON -- Use `misc/cleanup-dash.py` to normalize exported JSON before committing -- Follow the existing directory structure when adding dashboards for a new domain -- Keep one dashboard per JSON file, named to match the dashboard title -- Register new dashboards in `pmm-app/src/plugin.json` under the `includes` array - -### Don't -- Don't edit dashboard JSON by hand unless making targeted fixes — use the Grafana UI for design work -- Don't duplicate dashboard JSON inside `pmm-app/src/` — the canonical source is `dashboards/dashboards/` -- Don't commit Grafana-generated volatile fields (e.g., `version`, `iteration`) — use `cleanup-dash.py` to strip them - -## Key Files to Reference - -- `dashboards/dashboards/` — all dashboard JSON definitions, organized by domain -- `dashboards/pmm-app/src/plugin.json` — plugin manifest that registers dashboards in Grafana -- `dashboards/README.md` — featured dashboards list -- `dashboards/CONTRIBUTING.md` — contribution workflow and local dev setup diff --git a/dashboards/pmm-app/AGENTS.md b/dashboards/pmm-app/AGENTS.md deleted file mode 100644 index ead770e1b10..00000000000 --- a/dashboards/pmm-app/AGENTS.md +++ /dev/null @@ -1,146 +0,0 @@ -# QAN App (pmm-app) Development Guidelines - -> **Parent guide**: [AGENTS.md](../../AGENTS.md) — product overview, architecture, domain model, global conventions -> **Related**: [dashboards/dashboards/AGENTS.md](../dashboards/AGENTS.md) (dashboard JSON definitions bundled by this plugin) · [ui/AGENTS.md](../../ui/AGENTS.md) (main PMM frontend) · [api/AGENTS.md](../../api/AGENTS.md) (API definitions consumed by QAN) · [qan-api2/AGENTS.md](../../qan-api2/AGENTS.md) (QAN backend) - -The `dashboards/pmm-app/` directory contains a **Grafana application plugin** (`type: app`, `id: pmm-app`) that bundles PMM dashboard JSON definitions and provides the custom **Query Analytics (QAN) panel** (`pmm-qan-app-panel`). It is built with TypeScript and React on top of Grafana's plugin SDK. - -## Architecture - -### Plugin Structure - -The pmm-app plugin consists of two sub-plugins registered in their respective `plugin.json` manifests: - -1. **App plugin** (`pmm-app/src/plugin.json`) — declares the application, registers PMM dashboard JSON includes, and exposes the QAN panel. -2. **Panel plugin** (`pmm-app/src/pmm-qan/plugin.json`) — declares the `pmm-qan-app-panel` panel type used by `Query Analytics/pmm-qan.json`. - -``` -pmm-app/src/module.ts → AppPlugin() (minimal app shell) -pmm-app/src/pmm-qan/module.ts → PanelPlugin(QueryAnalyticsPanel) - -plugin.json includes[]: - - dashboards from dashboards/dashboards/**/*.json - - panel: pmm-qan-app-panel - -Build (webpack) → dist/ - → deployed to Grafana plugins directory on PMM Server -``` - -### Key Technology Choices - -| Technology | Role | -|------------|------| -| **TypeScript** | Type-safe development | -| **React 18** | UI framework | -| **Webpack** | Build tooling (Grafana plugin scaffolding) | -| **Yarn 1.x** | Package manager (`packageManager: yarn@1.22.21`) | -| **SCSS / LESS** | Styling | -| **@grafana/data, @grafana/ui, @grafana/runtime** | Grafana plugin SDK (`>=11.x.x`) | -| **Ant Design** | Additional UI components (QAN panel) | -| **axios** | HTTP client for QAN API calls | -| **react-table** | Table rendering in QAN Overview | -| **d3** | Data visualization | -| **Jest 29** | Unit testing (`@swc/jest`, `jest-environment-jsdom`) | - -## QAN Panel - -The Query Analytics panel lives in `pmm-app/src/pmm-qan/` and is registered as a `PanelPlugin` wrapping the `QueryAnalytics` React component. - -### Key Sub-Components - -| Component | Path | Purpose | -|-----------|------|---------| -| **QueryAnalytics** | `pmm-qan/panel/QueryAnalytics.tsx` | Root panel component | -| **Overview** | `pmm-qan/panel/components/Overview/` | Main query table with sortable metrics columns | -| **Details** | `pmm-qan/panel/components/Details/` | Query detail view: Explain, Metrics, Metadata, Table | -| **Filters** | `pmm-qan/panel/components/Filters/` | Filter sidebar (dimension, value filtering) | -| **BarChart** | `pmm-qan/panel/components/BarChart/` | Time-distribution bar chart | -| **ManageColumns** | `pmm-qan/panel/components/ManageColumns/` | Column visibility picker | - -### Shared Code - -`pmm-app/src/shared/` contains reusable code across the QAN panel: -- `components/` — common UI elements (Table, Modal, Charts, Icons, Form controls) -- `components/helpers/` — humanization, formatting, validators -- `components/hooks/` — shared React hooks (e.g., window size) -- `global-styles/themes/` — dark/light theme SCSS variables - -## Patterns and Conventions - -### Do -- Co-locate test files next to components (`*.test.tsx`) -- Use `@testing-library/react` for component tests -- Use `@grafana/data` and `@grafana/ui` APIs for Grafana integration -- Use the existing provider pattern in `pmm-qan/panel/provider/` for QAN state -- Follow the Grafana plugin SDK conventions for panel lifecycle - -### Don't -- Don't modify files under `.config/` — they are scaffolded by `@grafana/create-plugin` and carry "do not edit" warnings -- Don't introduce new state management libraries — use React state/context as in existing QAN code -- Don't duplicate dashboard JSON inside `pmm-app/src/` — the canonical source is `dashboards/dashboards/` -- Don't bypass the Grafana plugin SDK APIs for data queries or runtime services - -## Testing - -- **Framework**: Jest 29 with `@swc/jest` transform, `jest-environment-jsdom` -- **Libraries**: `@testing-library/react`, `@testing-library/jest-dom`, `@testing-library/user-event`, `jest-canvas-mock`, `mockdate` -- **Config**: `pmm-app/jest.config.js` extends `pmm-app/.config/jest.config.js`; sets `TZ=GMT` -- **Pattern**: ~35 co-located `*.test.tsx` / `*.test.ts` files under `pmm-app/src/` -- **Run**: `make test` (from `dashboards/`) or `yarn test:ci` (from `pmm-app/`) -- **Linting**: `yarn lint` runs ESLint on `src/**/*.{ts,tsx}`; `yarn typecheck` runs `tsc --noEmit` - -## Development Workflow - -```bash -# Prerequisites: Node >= 18, Yarn 1.x -cd dashboards/pmm-app - -# Install dependencies -yarn install --frozen-lockfile - -# Start webpack in watch mode (development) -yarn dev - -# Production build -yarn build - -# Run tests (CI mode) -yarn test:ci - -# Lint and typecheck -yarn lint && yarn typecheck -``` - -### Docker Development - -`pmm-app/docker-compose.yaml` provides a local Grafana environment that mounts `./dist` into the PMM Server plugin directory: - -```bash -cd dashboards/pmm-app -docker-compose up -d -yarn dev -``` - -### Makefile Targets (from `dashboards/`) - -| Target | Purpose | -|--------|---------| -| `make install` | `yarn install --frozen-lockfile` in `pmm-app/` | -| `make build` | `yarn build` in `pmm-app/` | -| `make release` | `install` + `build` | -| `make test` | `release` + `yarn test:ci` | -| `make clean` | Remove `pmm-app/dist/` | -| `make install-plugins` | Download ClickHouse and Polystat Grafana plugins | - -## Key Files to Reference - -- `dashboards/Makefile` — build, test, and release targets -- `dashboards/pmm-app/package.json` — dependencies, scripts, engine requirements -- `dashboards/pmm-app/src/plugin.json` — app plugin manifest (dashboard includes, panel registration) -- `dashboards/pmm-app/src/pmm-qan/plugin.json` — QAN panel plugin manifest -- `dashboards/pmm-app/src/module.ts` — app plugin entry point -- `dashboards/pmm-app/src/pmm-qan/module.ts` — QAN panel entry point -- `dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx` — root QAN panel component -- `dashboards/pmm-app/jest.config.js` — test configuration -- `dashboards/pmm-app/docker-compose.yaml` — local development environment -- `dashboards/CONTRIBUTING.md` — contribution workflow and local dev setup diff --git a/dashboards/pmm-app/src/dashboards b/dashboards/pmm-app/src/dashboards deleted file mode 120000 index 5f2b647e1da..00000000000 --- a/dashboards/pmm-app/src/dashboards +++ /dev/null @@ -1 +0,0 @@ -../../dashboards \ No newline at end of file diff --git a/ui/AGENTS.md b/ui/AGENTS.md index ce9318f1240..e307392790c 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -9,12 +9,13 @@ The `/ui` directory contains the PMM web frontend — a React/TypeScript applica ### Monorepo Structure -The UI uses a **Yarn workspaces + Turborepo** monorepo with three packages: +The UI uses a **Yarn workspaces + Turborepo** monorepo with four packages: | Package | Path | Purpose | | --------------- | --------------------- | ------------------------------------------------------------- | | **pmm** | `ui/apps/pmm/` | Main PMM UI application (Vite + React) | | **pmm-compat** | `ui/apps/pmm-compat/` | Grafana plugin for PMM ↔ Grafana integration (Webpack) | +| **pmm-app** | `ui/apps/pmm-app/` | Grafana app plugin bundling PMM dashboards and the Query Analytics panel (Webpack). See [ui/apps/pmm-app/AGENTS.md](apps/pmm-app/AGENTS.md). Its `src/dashboards` is a symlink to the top-level `/dashboards` folder, the canonical source of dashboard JSON. | | **@pmm/shared** | `ui/packages/shared/` | Shared code: cross-frame messaging, types, utilities (Rollup) | ### Key Technology Choices @@ -137,7 +138,7 @@ make build make test ``` -Inside the PMM devcontainer (`make env-up` then `make env` from the repo root), `make run-ui` (main UI HMR via Vite on port 5173) and `make run-qan-ui` (QAN livereload on port 35730) replace `make dev` and wire the dev servers into the bundled Grafana automatically. See `ui/README.md` for details. +Inside the PMM devcontainer (`make env-up` then `make env` from the repo root), `make run-ui` replaces `make dev` and wires all three dev servers into the bundled Grafana automatically: Vite HMR for the main UI (port 5173), and webpack + livereload for `pmm-compat` (port 35729) and `pmm-app`/QAN (port 35730), the latter also running a chokidar watcher that syncs dashboard JSON changes with no extra commands. See `ui/README.md` for details. ## Key Files to Reference diff --git a/dashboards/pmm-app/.config/.cprc.json b/ui/apps/pmm-app/.config/.cprc.json similarity index 100% rename from dashboards/pmm-app/.config/.cprc.json rename to ui/apps/pmm-app/.config/.cprc.json diff --git a/dashboards/pmm-app/.config/.eslintrc b/ui/apps/pmm-app/.config/.eslintrc similarity index 100% rename from dashboards/pmm-app/.config/.eslintrc rename to ui/apps/pmm-app/.config/.eslintrc diff --git a/dashboards/pmm-app/.config/.prettierrc.js b/ui/apps/pmm-app/.config/.prettierrc.js similarity index 100% rename from dashboards/pmm-app/.config/.prettierrc.js rename to ui/apps/pmm-app/.config/.prettierrc.js diff --git a/dashboards/pmm-app/.config/README.md b/ui/apps/pmm-app/.config/README.md similarity index 100% rename from dashboards/pmm-app/.config/README.md rename to ui/apps/pmm-app/.config/README.md diff --git a/dashboards/pmm-app/.config/jest-setup.js b/ui/apps/pmm-app/.config/jest-setup.js similarity index 100% rename from dashboards/pmm-app/.config/jest-setup.js rename to ui/apps/pmm-app/.config/jest-setup.js diff --git a/dashboards/pmm-app/.config/jest.config.js b/ui/apps/pmm-app/.config/jest.config.js similarity index 100% rename from dashboards/pmm-app/.config/jest.config.js rename to ui/apps/pmm-app/.config/jest.config.js diff --git a/dashboards/pmm-app/.config/jest/mocks/react-inlinesvg.tsx b/ui/apps/pmm-app/.config/jest/mocks/react-inlinesvg.tsx similarity index 100% rename from dashboards/pmm-app/.config/jest/mocks/react-inlinesvg.tsx rename to ui/apps/pmm-app/.config/jest/mocks/react-inlinesvg.tsx diff --git a/dashboards/pmm-app/.config/jest/utils.js b/ui/apps/pmm-app/.config/jest/utils.js similarity index 100% rename from dashboards/pmm-app/.config/jest/utils.js rename to ui/apps/pmm-app/.config/jest/utils.js diff --git a/dashboards/pmm-app/.config/tsconfig.json b/ui/apps/pmm-app/.config/tsconfig.json similarity index 100% rename from dashboards/pmm-app/.config/tsconfig.json rename to ui/apps/pmm-app/.config/tsconfig.json diff --git a/dashboards/pmm-app/.config/types/custom.d.ts b/ui/apps/pmm-app/.config/types/custom.d.ts similarity index 100% rename from dashboards/pmm-app/.config/types/custom.d.ts rename to ui/apps/pmm-app/.config/types/custom.d.ts diff --git a/dashboards/pmm-app/.config/webpack/constants.ts b/ui/apps/pmm-app/.config/webpack/constants.ts similarity index 100% rename from dashboards/pmm-app/.config/webpack/constants.ts rename to ui/apps/pmm-app/.config/webpack/constants.ts diff --git a/dashboards/pmm-app/.config/webpack/utils.ts b/ui/apps/pmm-app/.config/webpack/utils.ts similarity index 100% rename from dashboards/pmm-app/.config/webpack/utils.ts rename to ui/apps/pmm-app/.config/webpack/utils.ts diff --git a/dashboards/pmm-app/.config/webpack/webpack.config.ts b/ui/apps/pmm-app/.config/webpack/webpack.config.ts similarity index 100% rename from dashboards/pmm-app/.config/webpack/webpack.config.ts rename to ui/apps/pmm-app/.config/webpack/webpack.config.ts diff --git a/dashboards/pmm-app/.eslintrc b/ui/apps/pmm-app/.eslintrc similarity index 100% rename from dashboards/pmm-app/.eslintrc rename to ui/apps/pmm-app/.eslintrc diff --git a/ui/apps/pmm-app/.gitignore b/ui/apps/pmm-app/.gitignore new file mode 100644 index 00000000000..60e61b84705 --- /dev/null +++ b/ui/apps/pmm-app/.gitignore @@ -0,0 +1,8 @@ +# development +.env/ +docker-compose.*.y*ml + +# PMM-specific +video/ +pr.browsers.json +tests/output/ diff --git a/dashboards/pmm-app/.nvmrc b/ui/apps/pmm-app/.nvmrc similarity index 100% rename from dashboards/pmm-app/.nvmrc rename to ui/apps/pmm-app/.nvmrc diff --git a/dashboards/pmm-app/.prettierrc.js b/ui/apps/pmm-app/.prettierrc.js similarity index 100% rename from dashboards/pmm-app/.prettierrc.js rename to ui/apps/pmm-app/.prettierrc.js diff --git a/ui/apps/pmm-app/AGENTS.md b/ui/apps/pmm-app/AGENTS.md new file mode 100644 index 00000000000..350ca155525 --- /dev/null +++ b/ui/apps/pmm-app/AGENTS.md @@ -0,0 +1,143 @@ +# QAN App (pmm-app) Development Guidelines + +> **Parent guide**: [AGENTS.md](../../../AGENTS.md) — product overview, architecture, domain model, global conventions +> **Related**: [dashboards/AGENTS.md](../../../dashboards/AGENTS.md) (dashboard JSON definitions bundled by this plugin) · [ui/AGENTS.md](../../AGENTS.md) (main PMM frontend, monorepo this app is part of) · [api/AGENTS.md](../../../api/AGENTS.md) (API definitions consumed by QAN) · [qan-api2/AGENTS.md](../../../qan-api2/AGENTS.md) (QAN backend) + +The `ui/apps/pmm-app/` directory contains a **Grafana application plugin** (`type: app`, `id: pmm-app`) that bundles PMM dashboard JSON definitions and provides the custom **Query Analytics (QAN) panel** (`pmm-qan-app-panel`). It is built with TypeScript and React on top of Grafana's plugin SDK, and is a workspace member of the `ui/` Yarn workspaces + Turborepo monorepo (see [ui/AGENTS.md](../../AGENTS.md)). + +## Architecture + +### Plugin Structure + +The pmm-app plugin consists of two sub-plugins registered in their respective `plugin.json` manifests: + +1. **App plugin** (`src/plugin.json`) — declares the application, registers PMM dashboard JSON includes, and exposes the QAN panel. +2. **Panel plugin** (`src/pmm-qan/plugin.json`) — declares the `pmm-qan-app-panel` panel type used by `Query Analytics/pmm-qan.json`. + +``` +src/module.ts → AppPlugin() (minimal app shell) +src/pmm-qan/module.ts → PanelPlugin(QueryAnalyticsPanel) +src/dashboards → symlink to the top-level dashboards/ folder + +plugin.json includes[]: + - dashboards from dashboards/**/*.json (resolved through the src/dashboards symlink) + - panel: pmm-qan-app-panel + +Build (webpack) → dist/ + → deployed to Grafana plugins directory on PMM Server +``` + +### Key Technology Choices + +| Technology | Role | +|------------|------| +| **TypeScript** | Type-safe development | +| **React 18** | UI framework | +| **Webpack** | Build tooling (Grafana plugin scaffolding) | +| **Yarn 1.x** | Package manager, hoisted from the `ui/` workspace root | +| **SCSS / LESS** | Styling | +| **@grafana/data, @grafana/ui, @grafana/runtime** | Grafana plugin SDK (`>=11.x.x`) | +| **Ant Design** | Additional UI components (QAN panel) | +| **axios** | HTTP client for QAN API calls | +| **react-table** | Table rendering in QAN Overview | +| **d3** | Data visualization | +| **Jest 29** | Unit testing (`@swc/jest`, `jest-environment-jsdom`) | +| **chokidar** | Dashboard JSON file watcher for local dev (`scripts/watch-dashboards.mjs`) | + +## QAN Panel + +The Query Analytics panel lives in `src/pmm-qan/` and is registered as a `PanelPlugin` wrapping the `QueryAnalytics` React component. + +### Key Sub-Components + +| Component | Path | Purpose | +|-----------|------|---------| +| **QueryAnalytics** | `pmm-qan/panel/QueryAnalytics.tsx` | Root panel component | +| **Overview** | `pmm-qan/panel/components/Overview/` | Main query table with sortable metrics columns | +| **Details** | `pmm-qan/panel/components/Details/` | Query detail view: Explain, Metrics, Metadata, Table | +| **Filters** | `pmm-qan/panel/components/Filters/` | Filter sidebar (dimension, value filtering) | +| **BarChart** | `pmm-qan/panel/components/BarChart/` | Time-distribution bar chart | +| **ManageColumns** | `pmm-qan/panel/components/ManageColumns/` | Column visibility picker | + +### Shared Code + +`src/shared/` contains reusable code across the QAN panel: +- `components/` — common UI elements (Table, Modal, Charts, Icons, Form controls) +- `components/helpers/` — humanization, formatting, validators +- `components/hooks/` — shared React hooks (e.g., window size) +- `global-styles/themes/` — dark/light theme SCSS variables + +## Patterns and Conventions + +### Do +- Co-locate test files next to components (`*.test.tsx`) +- Use `@testing-library/react` for component tests +- Use `@grafana/data` and `@grafana/ui` APIs for Grafana integration +- Use the existing provider pattern in `pmm-qan/panel/provider/` for QAN state +- Follow the Grafana plugin SDK conventions for panel lifecycle + +### Don't +- Don't modify files under `.config/` — they are scaffolded by `@grafana/create-plugin` and carry "do not edit" warnings +- Don't introduce new state management libraries — use React state/context as in existing QAN code +- Don't duplicate dashboard JSON inside `src/` — the canonical source is the top-level `dashboards/` folder, reached through the `src/dashboards` symlink +- Don't bypass the Grafana plugin SDK APIs for data queries or runtime services + +## Testing + +- **Framework**: Jest 29 with `@swc/jest` transform, `jest-environment-jsdom` +- **Libraries**: `@testing-library/react`, `@testing-library/jest-dom`, `@testing-library/user-event`, `jest-canvas-mock`, `mockdate` +- **Config**: `jest.config.js` extends `.config/jest.config.js`; sets `TZ=GMT` +- **Pattern**: ~35 co-located `*.test.tsx` / `*.test.ts` files under `src/` +- **Run**: `yarn test` (one-shot) or `yarn test:watch` (watch mode) from `ui/apps/pmm-app/`, or `turbo run test --filter=pmm-app` from `ui/` +- **Linting**: `yarn lint` runs ESLint on `src/**/*.{ts,tsx}` (non-mutating; use `yarn lint:fix` to auto-fix); `yarn typecheck` runs `tsc --noEmit` + +## Development Workflow + +```bash +# Prerequisites: Node >= 18, Yarn 1.x +cd ui/apps/pmm-app + +# Install dependencies (or from ui/ to install the whole workspace) +yarn install + +# Start webpack in watch mode + the dashboard JSON watcher (development) +yarn dev + +# Production build +yarn build + +# Run tests (one-shot) +yarn test + +# Lint and typecheck +yarn lint && yarn typecheck +``` + +`yarn dev` runs two processes concurrently: webpack in watch mode with `webpack-livereload-plugin` (QAN JS/TS changes), and `scripts/watch-dashboards.mjs`, a chokidar watcher that mirrors dashboard JSON changes (reached through the `src/dashboards` symlink) into the Grafana-provisioned dashboards directory — both update automatically with no extra commands. + +### Docker Development + +`docker-compose.yaml` provides a local Grafana environment that mounts `./dist` into the PMM Server plugin directory: + +```bash +cd ui/apps/pmm-app +docker-compose up -d +yarn dev +``` + +### From the `ui/` monorepo + +Since this app is a `ui/` workspace member, the standard monorepo commands also work: `cd ui && yarn dev` (or `make run-ui` inside the devcontainer) starts this app's `dev` script alongside `pmm` and `pmm-compat` via Turborepo; `yarn build`/`yarn lint`/`yarn test` similarly fan out via `turbo run --filter=pmm-app` when scoped. + +## Key Files to Reference + +- `ui/apps/pmm-app/package.json` — dependencies, scripts, engine requirements +- `ui/apps/pmm-app/src/plugin.json` — app plugin manifest (dashboard includes, panel registration) +- `ui/apps/pmm-app/src/pmm-qan/plugin.json` — QAN panel plugin manifest +- `ui/apps/pmm-app/src/module.ts` — app plugin entry point +- `ui/apps/pmm-app/src/pmm-qan/module.ts` — QAN panel entry point +- `ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx` — root QAN panel component +- `ui/apps/pmm-app/jest.config.js` — test configuration +- `ui/apps/pmm-app/docker-compose.yaml` — local development environment +- `ui/apps/pmm-app/scripts/watch-dashboards.mjs` — dashboard JSON live-sync watcher +- `ui/apps/pmm-app/CONTRIBUTING.md` — contribution workflow and local dev setup diff --git a/dashboards/pmm-app/CHANGELOG.md b/ui/apps/pmm-app/CHANGELOG.md similarity index 100% rename from dashboards/pmm-app/CHANGELOG.md rename to ui/apps/pmm-app/CHANGELOG.md diff --git a/dashboards/pmm-app/CODE-STYLE.md b/ui/apps/pmm-app/CODE-STYLE.md similarity index 100% rename from dashboards/pmm-app/CODE-STYLE.md rename to ui/apps/pmm-app/CODE-STYLE.md diff --git a/dashboards/CONTRIBUTING.md b/ui/apps/pmm-app/CONTRIBUTING.md similarity index 100% rename from dashboards/CONTRIBUTING.md rename to ui/apps/pmm-app/CONTRIBUTING.md diff --git a/dashboards/pmm-app/LICENSE b/ui/apps/pmm-app/LICENSE similarity index 100% rename from dashboards/pmm-app/LICENSE rename to ui/apps/pmm-app/LICENSE diff --git a/dashboards/pmm-app/README.md b/ui/apps/pmm-app/README.md similarity index 100% rename from dashboards/pmm-app/README.md rename to ui/apps/pmm-app/README.md diff --git a/dashboards/codecov.yml b/ui/apps/pmm-app/codecov.yml similarity index 100% rename from dashboards/codecov.yml rename to ui/apps/pmm-app/codecov.yml diff --git a/dashboards/pmm-app/config/jest-setup.ts b/ui/apps/pmm-app/config/jest-setup.ts similarity index 100% rename from dashboards/pmm-app/config/jest-setup.ts rename to ui/apps/pmm-app/config/jest-setup.ts diff --git a/dashboards/pmm-app/docker-compose.yaml b/ui/apps/pmm-app/docker-compose.yaml similarity index 100% rename from dashboards/pmm-app/docker-compose.yaml rename to ui/apps/pmm-app/docker-compose.yaml diff --git a/dashboards/pmm-app/env.list b/ui/apps/pmm-app/env.list similarity index 100% rename from dashboards/pmm-app/env.list rename to ui/apps/pmm-app/env.list diff --git a/dashboards/pmm-app/jest-setup.js b/ui/apps/pmm-app/jest-setup.js similarity index 100% rename from dashboards/pmm-app/jest-setup.js rename to ui/apps/pmm-app/jest-setup.js diff --git a/dashboards/pmm-app/jest.config.js b/ui/apps/pmm-app/jest.config.js similarity index 100% rename from dashboards/pmm-app/jest.config.js rename to ui/apps/pmm-app/jest.config.js diff --git a/dashboards/pmm-app/package.json b/ui/apps/pmm-app/package.json similarity index 90% rename from dashboards/pmm-app/package.json rename to ui/apps/pmm-app/package.json index bb6efe67648..bfde8462f3f 100644 --- a/dashboards/pmm-app/package.json +++ b/ui/apps/pmm-app/package.json @@ -11,16 +11,16 @@ "main": "module.js", "scripts": { "build": "webpack -c ./.config/webpack/webpack.config.ts --env production", - "dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development", + "dev": "concurrently -k -n webpack,dashboards \"webpack -w -c ./.config/webpack/webpack.config.ts --env development\" \"node scripts/watch-dashboards.mjs\"", + "dev:webpack": "webpack -w -c ./.config/webpack/webpack.config.ts --env development", "jest": "jest", - "lint": "yarn lint:dev", - "lint:check": "eslint --ext .tsx,.ts src/", + "lint": "eslint --ext .tsx,.ts src/", "lint:dev": "eslint --ext .tsx,.ts --fix src/", - "lint:fix": "yarn run lint --fix", + "lint:fix": "yarn run lint:dev", "server": "docker-compose up --build", "sign": "npx --yes @grafana/sign-plugin@latest", - "test": "jest --watch --onlyChanged", - "test:ci": "jest --passWithNoTests --maxWorkers 4", + "test": "jest --passWithNoTests --maxWorkers 4", + "test:watch": "jest --watch --onlyChanged", "typecheck": "tsc --noEmit" }, "bin": { @@ -82,6 +82,8 @@ "@swc/core": "^1.3.90", "@swc/helpers": "^0.5.0", "@swc/jest": "^0.2.36", + "chokidar": "^3.6.0", + "concurrently": "^9.1.0", "@testing-library/jest-dom": "6.4.6", "@testing-library/react": "14.0.0", "@testing-library/react-hooks": "^3.2.1", diff --git a/ui/apps/pmm-app/scripts/watch-dashboards.mjs b/ui/apps/pmm-app/scripts/watch-dashboards.mjs new file mode 100644 index 00000000000..3aa021814b3 --- /dev/null +++ b/ui/apps/pmm-app/scripts/watch-dashboards.mjs @@ -0,0 +1,51 @@ +#!/usr/bin/env node +// Mirrors dashboard JSON changes from the top-level `dashboards/` folder (reached through the +// `src/dashboards` symlink) into the Grafana-provisioned dashboards directory, so edits show up +// without any manual `make reload-dashboards` step. Grafana's file provisioner polls that +// directory on its own (see build/ansible/roles/grafana/files/dashboards.yml), so a plain file +// copy is enough — no Grafana restart needed. +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; +import fs from 'node:fs/promises'; +import chokidar from 'chokidar'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const SOURCE_DIR = path.resolve(__dirname, '..', 'src', 'dashboards'); +const TARGET_DIR = + process.env.PERCONA_DASHBOARDS_DIST_DIR ?? '/usr/share/percona-dashboards/panels/pmm-app/dist/dashboards'; + +function targetPathFor(sourcePath) { + return path.join(TARGET_DIR, path.relative(SOURCE_DIR, sourcePath)); +} + +async function syncFile(sourcePath) { + const target = targetPathFor(sourcePath); + await fs.mkdir(path.dirname(target), { recursive: true }); + await fs.copyFile(sourcePath, target); +} + +async function removeFile(sourcePath) { + const target = targetPathFor(sourcePath); + await fs.rm(target, { force: true }); +} + +async function main() { + await fs.mkdir(TARGET_DIR, { recursive: true }).catch((err) => { + console.error( + `[watch-dashboards] Could not create target directory "${TARGET_DIR}": ${err.message}. ` + + 'Set PERCONA_DASHBOARDS_DIST_DIR to a writable path if you are not running inside the devcontainer.' + ); + process.exit(1); + }); + + const watcher = chokidar.watch(`${SOURCE_DIR}/**/*.json`, { ignoreInitial: false }); + + watcher + .on('add', (file) => syncFile(file).catch((err) => console.error(`[watch-dashboards] sync failed for ${file}:`, err.message))) + .on('change', (file) => syncFile(file).catch((err) => console.error(`[watch-dashboards] sync failed for ${file}:`, err.message))) + .on('unlink', (file) => removeFile(file).catch((err) => console.error(`[watch-dashboards] remove failed for ${file}:`, err.message))) + .on('ready', () => console.log(`[watch-dashboards] watching ${SOURCE_DIR} -> ${TARGET_DIR}`)) + .on('error', (err) => console.error('[watch-dashboards] watcher error:', err.message)); +} + +main(); diff --git a/dashboards/pmm-app/src/__mocks__/react-inlinesvg.tsx b/ui/apps/pmm-app/src/__mocks__/react-inlinesvg.tsx similarity index 100% rename from dashboards/pmm-app/src/__mocks__/react-inlinesvg.tsx rename to ui/apps/pmm-app/src/__mocks__/react-inlinesvg.tsx diff --git a/ui/apps/pmm-app/src/dashboards b/ui/apps/pmm-app/src/dashboards new file mode 120000 index 00000000000..9791cdc4da5 --- /dev/null +++ b/ui/apps/pmm-app/src/dashboards @@ -0,0 +1 @@ +../../../../dashboards \ No newline at end of file diff --git a/dashboards/pmm-app/src/img/pmm-logo.svg b/ui/apps/pmm-app/src/img/pmm-logo.svg similarity index 100% rename from dashboards/pmm-app/src/img/pmm-logo.svg rename to ui/apps/pmm-app/src/img/pmm-logo.svg diff --git a/dashboards/pmm-app/src/module.ts b/ui/apps/pmm-app/src/module.ts similarity index 100% rename from dashboards/pmm-app/src/module.ts rename to ui/apps/pmm-app/src/module.ts diff --git a/dashboards/pmm-app/src/plugin.json b/ui/apps/pmm-app/src/plugin.json similarity index 100% rename from dashboards/pmm-app/src/plugin.json rename to ui/apps/pmm-app/src/plugin.json diff --git a/dashboards/pmm-app/src/pmm-qan/module.ts b/ui/apps/pmm-app/src/pmm-qan/module.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/module.ts rename to ui/apps/pmm-app/src/pmm-qan/module.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.messages.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.messages.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.messages.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Details.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.messages.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.messages.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.messages.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/ParseError/ParseError.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.hooks.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.hooks.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.hooks.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.test.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.test.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.test.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.test.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/JsonExplain/JsonExplain.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ReplacedQueryMessage/ReplacedQueryMessage.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/VisualExplain/VisualExplain.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/ExplainPlaceholders.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.messages.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.messages.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.messages.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.utils.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.utils.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.utils.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.utils.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.utils.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.utils.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.test.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.test.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.test.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.test.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.utils.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/__mocks__/histogramStubs.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/__mocks__/histogramStubs.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/__mocks__/histogramStubs.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/__mocks__/histogramStubs.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.messages.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.messages.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.messages.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/Plan.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/Plan.hooks.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/Plan.hooks.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/Plan.hooks.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/planStubs.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/planStubs.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/planStubs.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/__mocks__/planStubs.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.hooks.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.hooks.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.hooks.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.hooks.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.hooks.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.hooks.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.hooks.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.hooks.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Table.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Table.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Table.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Table.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.hooks.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.hooks.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.hooks.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.hooks.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/mongodb.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/mongodb.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/mongodb.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/mongodb.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mongodb/service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.utils.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.utils.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/mysql.utils.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/mysql/service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/postgresql.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/postgresql.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/postgresql.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/postgresql.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/postgresql/service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.test.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.test.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.test.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.test.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/database-models/utils.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Details/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Details/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Details/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.messages.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.messages.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.messages.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/Filters.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/hooks/__mocks__/useFilters.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/hooks/__mocks__/useFilters.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/hooks/__mocks__/useFilters.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/hooks/__mocks__/useFilters.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useFilters.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useFilters.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useFilters.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useFilters.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useInitialFilterValues.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useInitialFilterValues.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useInitialFilterValues.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/hooks/useInitialFilterValues.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Filters/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Filters/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.scss b/ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.scss similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.scss rename to ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.scss diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/ManageColumns.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/ManageColumns/OptionContent/OptionContent.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.hooks.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.hooks.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.hooks.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.messages.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.messages.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.messages.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.scss b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.scss similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.scss rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.scss diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.service.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.service.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.service.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/Overview.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/Overview.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/DefaultColumns/DefaultColumns.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.scss b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.scss similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.scss rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.scss diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Dimension/Dimension.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumn.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumn.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumn.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumn.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.scss b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.scss similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.scss rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.scss diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/MetricColumns/MetricColumns.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.constants.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.constants.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.constants.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/Table.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/QanTable/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.styles.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.styles.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.styles.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.test.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.test.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.test.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/components/Search/Search.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/Overview/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/Overview/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/Overview/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/components/index.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/index.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/components/index.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/components/index.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/provider/provider.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/provider/provider.tools.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/provider/provider.tools.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/provider/provider.tools.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/provider/provider.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/provider/provider.tsx similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/provider/provider.tsx rename to ui/apps/pmm-app/src/pmm-qan/panel/provider/provider.tsx diff --git a/dashboards/pmm-app/src/pmm-qan/panel/provider/provider.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/provider/provider.types.ts similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/provider/provider.types.ts rename to ui/apps/pmm-app/src/pmm-qan/panel/provider/provider.types.ts diff --git a/dashboards/pmm-app/src/pmm-qan/panel/qan.scss b/ui/apps/pmm-app/src/pmm-qan/panel/qan.scss similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/panel/qan.scss rename to ui/apps/pmm-app/src/pmm-qan/panel/qan.scss diff --git a/dashboards/pmm-app/src/pmm-qan/plugin.json b/ui/apps/pmm-app/src/pmm-qan/plugin.json similarity index 100% rename from dashboards/pmm-app/src/pmm-qan/plugin.json rename to ui/apps/pmm-app/src/pmm-qan/plugin.json diff --git a/dashboards/pmm-app/src/shared/assets/fonts/Roboto/LICENSE.txt b/ui/apps/pmm-app/src/shared/assets/fonts/Roboto/LICENSE.txt similarity index 100% rename from dashboards/pmm-app/src/shared/assets/fonts/Roboto/LICENSE.txt rename to ui/apps/pmm-app/src/shared/assets/fonts/Roboto/LICENSE.txt diff --git a/dashboards/pmm-app/src/shared/assets/fonts/Roboto/Roboto-Regular.ttf b/ui/apps/pmm-app/src/shared/assets/fonts/Roboto/Roboto-Regular.ttf similarity index 100% rename from dashboards/pmm-app/src/shared/assets/fonts/Roboto/Roboto-Regular.ttf rename to ui/apps/pmm-app/src/shared/assets/fonts/Roboto/Roboto-Regular.ttf diff --git a/dashboards/pmm-app/src/shared/assets/pmm-logo.svg b/ui/apps/pmm-app/src/shared/assets/pmm-logo.svg similarity index 100% rename from dashboards/pmm-app/src/shared/assets/pmm-logo.svg rename to ui/apps/pmm-app/src/shared/assets/pmm-logo.svg diff --git a/dashboards/pmm-app/src/shared/components/Actions/Actions.service.ts b/ui/apps/pmm-app/src/shared/components/Actions/Actions.service.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Actions/Actions.service.ts rename to ui/apps/pmm-app/src/shared/components/Actions/Actions.service.ts diff --git a/dashboards/pmm-app/src/shared/components/Actions/Actions.types.ts b/ui/apps/pmm-app/src/shared/components/Actions/Actions.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Actions/Actions.types.ts rename to ui/apps/pmm-app/src/shared/components/Actions/Actions.types.ts diff --git a/dashboards/pmm-app/src/shared/components/Actions/Actions.utils.ts b/ui/apps/pmm-app/src/shared/components/Actions/Actions.utils.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Actions/Actions.utils.ts rename to ui/apps/pmm-app/src/shared/components/Actions/Actions.utils.ts diff --git a/dashboards/pmm-app/src/shared/components/Actions/index.ts b/ui/apps/pmm-app/src/shared/components/Actions/index.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Actions/index.ts rename to ui/apps/pmm-app/src/shared/components/Actions/index.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/Latency/Latency.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tools.ts b/ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tools.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tools.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tools.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.types.ts b/ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.types.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/Sparkline/Sparkline.types.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.constants.ts b/ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.constants.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.constants.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.constants.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.test.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.test.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/TimeDistribution.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/__snapshots__/TimeDistribution.test.tsx.snap b/ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/__snapshots__/TimeDistribution.test.tsx.snap similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/__snapshots__/TimeDistribution.test.tsx.snap rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/TimeDistribution/__snapshots__/TimeDistribution.test.tsx.snap diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.scss b/ui/apps/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.scss similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.scss rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.scss diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/TotalPercentage/TotalPercentage.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Charts/index.ts b/ui/apps/pmm-app/src/shared/components/Elements/Charts/index.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Charts/index.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Charts/index.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/Close.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Icons/Close.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/Close.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/Close.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/Database.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Icons/Database.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/Database.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/Database.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/Filter.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Icons/Filter.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/Filter.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/Filter.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/Icons.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/Icons/Icons.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/Icons.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/Icons.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/Icons.types.ts b/ui/apps/pmm-app/src/shared/components/Elements/Icons/Icons.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/Icons.types.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/Icons.types.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/Info.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Icons/Info.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/Info.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/Info.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/Search.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Icons/Search.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/Search.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/Search.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Icons/index.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Icons/index.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Icons/index.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Icons/index.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.test.tsx b/ui/apps/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.test.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.tsx b/ui/apps/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/LinkTooltip/LinkTooltip.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Modal/Modal.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Modal/Modal.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Modal/Modal.test.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Modal/Modal.test.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Modal/Modal.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Modal/Modal.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooltip.test.tsx b/ui/apps/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooltip.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooltip.test.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooltip.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooptip.tsx b/ui/apps/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooptip.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooptip.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/OverflowTooltip/OverflowTooptip.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/OverflowTooltip/__snapshots__/OverflowTooltip.test.tsx.snap b/ui/apps/pmm-app/src/shared/components/Elements/OverflowTooltip/__snapshots__/OverflowTooltip.test.tsx.snap similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/OverflowTooltip/__snapshots__/OverflowTooltip.test.tsx.snap rename to ui/apps/pmm-app/src/shared/components/Elements/OverflowTooltip/__snapshots__/OverflowTooltip.test.tsx.snap diff --git a/dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.test.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.test.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.types.ts b/ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Overlay/Overlay.types.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Overlay/Overlay.types.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.tsx b/ui/apps/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/QueryTooltip/QueryTooltip.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/ReactJSON/ReactJSON.tsx b/ui/apps/pmm-app/src/shared/components/Elements/ReactJSON/ReactJSON.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/ReactJSON/ReactJSON.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/ReactJSON/ReactJSON.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.styles.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.styles.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.styles.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.styles.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Scrollbar/Scrollbar.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Scrollbar/__mocks__/Scrollbar.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Scrollbar/__mocks__/Scrollbar.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Scrollbar/__mocks__/Scrollbar.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Scrollbar/__mocks__/Scrollbar.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Spinner/Spinner.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Spinner/Spinner.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Spinner/Spinner.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Spinner/Spinner.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Table/Table.styles.ts b/ui/apps/pmm-app/src/shared/components/Elements/Table/Table.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Table/Table.styles.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Table/Table.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Table/Table.test.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Table/Table.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Table/Table.test.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Table/Table.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Table/Table.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Table/Table.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Table/Table.tsx rename to ui/apps/pmm-app/src/shared/components/Elements/Table/Table.tsx diff --git a/dashboards/pmm-app/src/shared/components/Elements/Table/Table.types.ts b/ui/apps/pmm-app/src/shared/components/Elements/Table/Table.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Table/Table.types.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Table/Table.types.ts diff --git a/dashboards/pmm-app/src/shared/components/Elements/Table/index.ts b/ui/apps/pmm-app/src/shared/components/Elements/Table/index.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Elements/Table/index.ts rename to ui/apps/pmm-app/src/shared/components/Elements/Table/index.ts diff --git a/dashboards/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.styles.ts b/ui/apps/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.styles.ts rename to ui/apps/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.test.tsx b/ui/apps/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.test.tsx rename to ui/apps/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.tsx b/ui/apps/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.tsx rename to ui/apps/pmm-app/src/shared/components/Form/ButtonWithSpinner/ButtonWithSpinner.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.styles.tsx b/ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.styles.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.styles.tsx rename to ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.styles.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.test.tsx b/ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.test.tsx rename to ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.tsx b/ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.tsx rename to ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.types.ts b/ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Checkbox/Checkbox.types.ts rename to ui/apps/pmm-app/src/shared/components/Form/Checkbox/Checkbox.types.ts diff --git a/dashboards/pmm-app/src/shared/components/Form/Checkbox/__snapshots__/Checkbox.test.tsx.snap b/ui/apps/pmm-app/src/shared/components/Form/Checkbox/__snapshots__/Checkbox.test.tsx.snap similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Checkbox/__snapshots__/Checkbox.test.tsx.snap rename to ui/apps/pmm-app/src/shared/components/Form/Checkbox/__snapshots__/Checkbox.test.tsx.snap diff --git a/dashboards/pmm-app/src/shared/components/Form/FieldAdapters/Checkbox.tsx b/ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/Checkbox.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/FieldAdapters/Checkbox.tsx rename to ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/Checkbox.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/FieldAdapters/Field.tsx b/ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/Field.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/FieldAdapters/Field.tsx rename to ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/Field.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.styles.ts b/ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.styles.ts rename to ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.tsx b/ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.tsx rename to ui/apps/pmm-app/src/shared/components/Form/FieldAdapters/FieldAdapters.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/FormElement/FormElement.tsx b/ui/apps/pmm-app/src/shared/components/Form/FormElement/FormElement.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/FormElement/FormElement.tsx rename to ui/apps/pmm-app/src/shared/components/Form/FormElement/FormElement.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Radio/RadioButton.styles.ts b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Radio/RadioButton.styles.ts rename to ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx rename to ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Radio/RadioButton.tsx b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Radio/RadioButton.tsx rename to ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts rename to ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.test.tsx b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.test.tsx rename to ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx rename to ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx diff --git a/dashboards/pmm-app/src/shared/components/Form/index.ts b/ui/apps/pmm-app/src/shared/components/Form/index.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Form/index.ts rename to ui/apps/pmm-app/src/shared/components/Form/index.ts diff --git a/dashboards/pmm-app/src/shared/components/Hightlight/Highlight.styles.ts b/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.styles.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Hightlight/Highlight.styles.ts rename to ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.styles.ts diff --git a/dashboards/pmm-app/src/shared/components/Hightlight/Highlight.test.tsx b/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Hightlight/Highlight.test.tsx rename to ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/Hightlight/Highlight.tsx b/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/Hightlight/Highlight.tsx rename to ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.tsx diff --git a/dashboards/pmm-app/src/shared/components/Hightlight/Highlight.types.ts b/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/Hightlight/Highlight.types.ts rename to ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.types.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/Helpers.test.tsx b/ui/apps/pmm-app/src/shared/components/helpers/Helpers.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/Helpers.test.tsx rename to ui/apps/pmm-app/src/shared/components/helpers/Helpers.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/helpers/Helpers.tsx b/ui/apps/pmm-app/src/shared/components/helpers/Helpers.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/Helpers.tsx rename to ui/apps/pmm-app/src/shared/components/helpers/Helpers.tsx diff --git a/dashboards/pmm-app/src/shared/components/helpers/Humanization.test.ts b/ui/apps/pmm-app/src/shared/components/helpers/Humanization.test.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/Humanization.test.ts rename to ui/apps/pmm-app/src/shared/components/helpers/Humanization.test.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/Humanization.ts b/ui/apps/pmm-app/src/shared/components/helpers/Humanization.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/Humanization.ts rename to ui/apps/pmm-app/src/shared/components/helpers/Humanization.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/__mocks__/notification-manager.ts b/ui/apps/pmm-app/src/shared/components/helpers/__mocks__/notification-manager.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/__mocks__/notification-manager.ts rename to ui/apps/pmm-app/src/shared/components/helpers/__mocks__/notification-manager.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap b/ui/apps/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap rename to ui/apps/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap diff --git a/dashboards/pmm-app/src/shared/components/helpers/api.test.ts b/ui/apps/pmm-app/src/shared/components/helpers/api.test.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/api.test.ts rename to ui/apps/pmm-app/src/shared/components/helpers/api.test.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/api.ts b/ui/apps/pmm-app/src/shared/components/helpers/api.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/api.ts rename to ui/apps/pmm-app/src/shared/components/helpers/api.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/getPmmTheme.ts b/ui/apps/pmm-app/src/shared/components/helpers/getPmmTheme.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/getPmmTheme.ts rename to ui/apps/pmm-app/src/shared/components/helpers/getPmmTheme.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/index.ts b/ui/apps/pmm-app/src/shared/components/helpers/index.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/index.ts rename to ui/apps/pmm-app/src/shared/components/helpers/index.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/notification-manager.ts b/ui/apps/pmm-app/src/shared/components/helpers/notification-manager.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/notification-manager.ts rename to ui/apps/pmm-app/src/shared/components/helpers/notification-manager.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/processMetrics.ts b/ui/apps/pmm-app/src/shared/components/helpers/processMetrics.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/processMetrics.ts rename to ui/apps/pmm-app/src/shared/components/helpers/processMetrics.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/promises.test.tsx b/ui/apps/pmm-app/src/shared/components/helpers/promises.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/promises.test.tsx rename to ui/apps/pmm-app/src/shared/components/helpers/promises.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/helpers/promises.ts b/ui/apps/pmm-app/src/shared/components/helpers/promises.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/promises.ts rename to ui/apps/pmm-app/src/shared/components/helpers/promises.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/time-parameters-parser.test.ts b/ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.test.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/time-parameters-parser.test.ts rename to ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.test.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/time-parameters-parser.ts b/ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/time-parameters-parser.ts rename to ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/validator.types.ts b/ui/apps/pmm-app/src/shared/components/helpers/validator.types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/validator.types.ts rename to ui/apps/pmm-app/src/shared/components/helpers/validator.types.ts diff --git a/dashboards/pmm-app/src/shared/components/helpers/validators.test.tsx b/ui/apps/pmm-app/src/shared/components/helpers/validators.test.tsx similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/validators.test.tsx rename to ui/apps/pmm-app/src/shared/components/helpers/validators.test.tsx diff --git a/dashboards/pmm-app/src/shared/components/helpers/validators.ts b/ui/apps/pmm-app/src/shared/components/helpers/validators.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/helpers/validators.ts rename to ui/apps/pmm-app/src/shared/components/helpers/validators.ts diff --git a/dashboards/pmm-app/src/shared/components/hooks/WindowSize.hooks.ts b/ui/apps/pmm-app/src/shared/components/hooks/WindowSize.hooks.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/hooks/WindowSize.hooks.ts rename to ui/apps/pmm-app/src/shared/components/hooks/WindowSize.hooks.ts diff --git a/dashboards/pmm-app/src/shared/components/hooks/__mocks__/parameters.hook.ts b/ui/apps/pmm-app/src/shared/components/hooks/__mocks__/parameters.hook.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/hooks/__mocks__/parameters.hook.ts rename to ui/apps/pmm-app/src/shared/components/hooks/__mocks__/parameters.hook.ts diff --git a/dashboards/pmm-app/src/shared/components/hooks/parameters.hook.ts b/ui/apps/pmm-app/src/shared/components/hooks/parameters.hook.ts similarity index 100% rename from dashboards/pmm-app/src/shared/components/hooks/parameters.hook.ts rename to ui/apps/pmm-app/src/shared/components/hooks/parameters.hook.ts diff --git a/dashboards/pmm-app/src/shared/core/Settings.service.ts b/ui/apps/pmm-app/src/shared/core/Settings.service.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/Settings.service.ts rename to ui/apps/pmm-app/src/shared/core/Settings.service.ts diff --git a/dashboards/pmm-app/src/shared/core/__mocks__/Settings.service.ts b/ui/apps/pmm-app/src/shared/core/__mocks__/Settings.service.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/__mocks__/Settings.service.ts rename to ui/apps/pmm-app/src/shared/core/__mocks__/Settings.service.ts diff --git a/dashboards/pmm-app/src/shared/core/__mocks__/logger.ts b/ui/apps/pmm-app/src/shared/core/__mocks__/logger.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/__mocks__/logger.ts rename to ui/apps/pmm-app/src/shared/core/__mocks__/logger.ts diff --git a/dashboards/pmm-app/src/shared/core/constants.ts b/ui/apps/pmm-app/src/shared/core/constants.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/constants.ts rename to ui/apps/pmm-app/src/shared/core/constants.ts diff --git a/dashboards/pmm-app/src/shared/core/index.ts b/ui/apps/pmm-app/src/shared/core/index.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/index.ts rename to ui/apps/pmm-app/src/shared/core/index.ts diff --git a/dashboards/pmm-app/src/shared/core/logger.ts b/ui/apps/pmm-app/src/shared/core/logger.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/logger.ts rename to ui/apps/pmm-app/src/shared/core/logger.ts diff --git a/dashboards/pmm-app/src/shared/core/theme.ts b/ui/apps/pmm-app/src/shared/core/theme.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/theme.ts rename to ui/apps/pmm-app/src/shared/core/theme.ts diff --git a/dashboards/pmm-app/src/shared/core/types.ts b/ui/apps/pmm-app/src/shared/core/types.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/types.ts rename to ui/apps/pmm-app/src/shared/core/types.ts diff --git a/dashboards/pmm-app/src/shared/core/utils.ts b/ui/apps/pmm-app/src/shared/core/utils.ts similarity index 100% rename from dashboards/pmm-app/src/shared/core/utils.ts rename to ui/apps/pmm-app/src/shared/core/utils.ts diff --git a/dashboards/pmm-app/src/shared/global-styles/buttons.scss b/ui/apps/pmm-app/src/shared/global-styles/buttons.scss similarity index 100% rename from dashboards/pmm-app/src/shared/global-styles/buttons.scss rename to ui/apps/pmm-app/src/shared/global-styles/buttons.scss diff --git a/dashboards/pmm-app/src/shared/global-styles/charts.scss b/ui/apps/pmm-app/src/shared/global-styles/charts.scss similarity index 100% rename from dashboards/pmm-app/src/shared/global-styles/charts.scss rename to ui/apps/pmm-app/src/shared/global-styles/charts.scss diff --git a/dashboards/pmm-app/src/shared/global-styles/fonts.css b/ui/apps/pmm-app/src/shared/global-styles/fonts.css similarity index 100% rename from dashboards/pmm-app/src/shared/global-styles/fonts.css rename to ui/apps/pmm-app/src/shared/global-styles/fonts.css diff --git a/dashboards/pmm-app/src/shared/global-styles/spinner.scss b/ui/apps/pmm-app/src/shared/global-styles/spinner.scss similarity index 100% rename from dashboards/pmm-app/src/shared/global-styles/spinner.scss rename to ui/apps/pmm-app/src/shared/global-styles/spinner.scss diff --git a/dashboards/pmm-app/src/shared/global-styles/themes/theme-dark.scss b/ui/apps/pmm-app/src/shared/global-styles/themes/theme-dark.scss similarity index 100% rename from dashboards/pmm-app/src/shared/global-styles/themes/theme-dark.scss rename to ui/apps/pmm-app/src/shared/global-styles/themes/theme-dark.scss diff --git a/dashboards/pmm-app/src/shared/global-styles/themes/theme-light.scss b/ui/apps/pmm-app/src/shared/global-styles/themes/theme-light.scss similarity index 100% rename from dashboards/pmm-app/src/shared/global-styles/themes/theme-light.scss rename to ui/apps/pmm-app/src/shared/global-styles/themes/theme-light.scss diff --git a/dashboards/pmm-app/src/shared/global-styles/variables.scss b/ui/apps/pmm-app/src/shared/global-styles/variables.scss similarity index 100% rename from dashboards/pmm-app/src/shared/global-styles/variables.scss rename to ui/apps/pmm-app/src/shared/global-styles/variables.scss diff --git a/dashboards/pmm-app/src/shared/style.less b/ui/apps/pmm-app/src/shared/style.less similarity index 100% rename from dashboards/pmm-app/src/shared/style.less rename to ui/apps/pmm-app/src/shared/style.less diff --git a/dashboards/pmm-app/src/shared/styles.scss b/ui/apps/pmm-app/src/shared/styles.scss similarity index 100% rename from dashboards/pmm-app/src/shared/styles.scss rename to ui/apps/pmm-app/src/shared/styles.scss diff --git a/dashboards/pmm-app/tsconfig.json b/ui/apps/pmm-app/tsconfig.json similarity index 100% rename from dashboards/pmm-app/tsconfig.json rename to ui/apps/pmm-app/tsconfig.json diff --git a/dashboards/pmm-app/yarn.lock b/ui/apps/pmm-app/yarn.lock similarity index 100% rename from dashboards/pmm-app/yarn.lock rename to ui/apps/pmm-app/yarn.lock From 21de7c2e3405be6f2e5e347265068a0090652635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Silva?= Date: Thu, 30 Jul 2026 17:46:57 +0000 Subject: [PATCH 02/10] Update CONTRIBUTING.md references to the new run-ui/pmm-app paths Follow-up to the previous commit: these two docs still pointed at the retired make run-qan-ui/build-qan-ui targets and the old dashboards/pmm-app path. --- CONTRIBUTING.md | 4 ++-- ui/apps/pmm-app/CONTRIBUTING.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c293361e132..a7bac6e195f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -136,10 +136,10 @@ Exporters are independent applications, so each of them contains its own README ### UI -The devcontainer ships NodeJS and Yarn out of the box and exposes Vite (`make run-ui`) for the main PMM UI and webpack + livereload (`make run-qan-ui`) for the QAN Grafana plugin. See: +The devcontainer ships NodeJS and Yarn out of the box and `make run-ui` starts all of it: Vite (main PMM UI), webpack + livereload (`pmm-compat` and the QAN Grafana plugin), and a watcher that syncs dashboard JSON changes automatically. See: - [`ui/README.md`](https://github.com/percona/pmm/tree/main/ui/README.md) — main PMM UI (Vite, React, MUI). -- [`dashboards/CONTRIBUTING.md`](https://github.com/percona/pmm/tree/main/dashboards/CONTRIBUTING.md) — QAN plugin and Grafana dashboards. +- [`ui/apps/pmm-app/CONTRIBUTING.md`](https://github.com/percona/pmm/tree/main/ui/apps/pmm-app/CONTRIBUTING.md) — QAN plugin and Grafana dashboards. Both docs cover the devcontainer flow and the host-local alternative. diff --git a/ui/apps/pmm-app/CONTRIBUTING.md b/ui/apps/pmm-app/CONTRIBUTING.md index 936d96db616..4cea63089bd 100644 --- a/ui/apps/pmm-app/CONTRIBUTING.md +++ b/ui/apps/pmm-app/CONTRIBUTING.md @@ -47,14 +47,14 @@ make env # shell into the container Then **inside the container**: ```bash -make run-qan-ui +make run-ui ``` -`run-qan-ui` runs `yarn install` under `dashboards/pmm-app`, symlinks `dashboards/pmm-app/dist` into `/srv/grafana/plugins/pmm-app/dist`, injects the livereload snippet into Grafana's `index.html` via `setup-livereload`, and starts the webpack watcher. +`run-ui` installs dependencies for the whole `ui/` workspace (including this app), symlinks `ui/apps/pmm-app/dist` into `/srv/grafana/plugins/pmm-app/dist`, injects the livereload snippet into Grafana's `index.html` via `setup-livereload`, and starts every app's dev script through Turborepo — for `pmm-app` that's the webpack watcher plus a chokidar-based watcher that syncs dashboard JSON changes automatically. -Open `https://localhost/graph/d/pmm-qan/` — the livereload server on port `35730` reloads the page whenever webpack finishes a rebuild. +Open `https://localhost/graph/d/pmm-qan/` — the livereload server on port `35730` reloads the page whenever webpack finishes a rebuild, and dashboard JSON edits show up within Grafana's normal 60s provisioning poll with no extra commands. -For a one-off build (no watch), use `make build-qan-ui` instead. +For a one-off build (no watch), use `make build-ui` instead. ### Standalone with Docker Compose From 4b30357b490a8a0cad2df2863956c231140c0bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Silva?= Date: Thu, 30 Jul 2026 17:54:37 +0000 Subject: [PATCH 03/10] PMM-15028 Update CI workflows, RPM spec and CODEOWNERS for the pmm-app move Follow-up to the dashboards/pmm-app restructuring: wires up the three pieces that were previously deferred because they needed a real CI run or RPM build to validate. - .github/workflows/dashboards.yml: drop the build/tests jobs (pmm-app lint/test/build is now covered by ui.yml via Turborepo), fix the changed-dashboard-files path pattern for the flattened dashboards/ tree, and repoint the Slack notification jobs at the check job. - .github/workflows/ui.yml: stop ignoring dashboards/** changes (a deleted/renamed dashboard JSON can break plugin.json includes), and add the plugin.json path verification step, fixed to check paths directly against the repo root instead of double-prefixing them with dashboards/. - build/packages/rpm/server/SPECS/percona-dashboards.spec: build ui/apps/pmm-app via turbo instead of the now-gone dashboards/Makefile, and package its dist/ output from the new location. %license/%doc keep pointing at dashboards/LICENSE and dashboards/README.md, which were deliberately kept there for this reason. - .github/CODEOWNERS: give ui/apps/pmm-app/ its own entry so QAN review routing isn't silently absorbed by the generic /ui/ rule. --- .github/CODEOWNERS | 1 + .github/workflows/dashboards.yml | 79 +------------------ .github/workflows/ui.yml | 12 ++- .../rpm/server/SPECS/percona-dashboards.spec | 9 ++- 4 files changed, 21 insertions(+), 80 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 19a2e994dd6..e8b77d8d624 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,6 +2,7 @@ /dev/docs/ @percona/pmm-review-be /documentation/ @percona/pmm-docs /ui/ @percona/pmm-review-fe +/ui/apps/pmm-app/ @nailya @percona/pmm-review-fe /dashboards/ @nailya @percona/pmm-review-fe /api/ @percona/pmm-review-be **/go.mod @percona/pmm-review-be diff --git a/.github/workflows/dashboards.yml b/.github/workflows/dashboards.yml index 6f8ff7d7813..457794c531f 100644 --- a/.github/workflows/dashboards.yml +++ b/.github/workflows/dashboards.yml @@ -9,79 +9,6 @@ permissions: contents: read jobs: - build: - name: Build - runs-on: ubuntu-latest - permissions: - actions: write - - steps: - - name: Checkout code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Install NodeJS - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: "22" - cache: "yarn" - cache-dependency-path: dashboards/pmm-app/yarn.lock - - - name: Verify plugin.json dashboard paths exist - run: | - missing=$(jq -r '.includes[] | select(.path) | .path' dashboards/pmm-app/src/plugin.json \ - | while read -r p; do [ -f "dashboards/$p" ] || echo "$p"; done) - if [ -n "$missing" ]; then - echo "::error::plugin.json references dashboard files that do not exist:" - echo "$missing" | sed 's/^/ - /' - exit 1 - fi - - - name: Install deps - run: make -C dashboards install - - - name: Build Grafana Dashboards - run: make -C dashboards build - - - name: Upload the build artefacts - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: build-dist - path: dashboards/pmm-app/dist/ - if-no-files-found: error - - tests: - name: Tests - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Install NodeJS - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: "22" - cache: "yarn" - cache-dependency-path: dashboards/pmm-app/yarn.lock - - - name: Install deps - run: make -C dashboards install - - - name: Run lint - run: cd dashboards/pmm-app && yarn lint:check - - - name: Run unit tests - run: cd dashboards/pmm-app && yarn test:ci - - - name: Upload unit test coverage - if: github.event.pull_request.head.repo.full_name == github.repository - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 - with: - fail_ci_if_error: true - flags: unittests # optional - name: codecov-umbrella - token: ${{ secrets.CODECOV_TOKEN }} - verbose: true - check: name: Check runs-on: ubuntu-latest @@ -95,7 +22,7 @@ jobs: id: changed run: | git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD \ - | grep -E '^dashboards/dashboards/.*\.json$' \ + | grep -E '^dashboards/.*\.json$' \ | sort -u > changed_dashboards.txt || true echo "count=$(wc -l < changed_dashboards.txt | tr -d ' ')" >> $GITHUB_OUTPUT @@ -131,7 +58,7 @@ jobs: fi workflow_success: - needs: [tests, build] + needs: [check] name: Slack Notification success runs-on: ubuntu-latest env: @@ -149,7 +76,7 @@ jobs: workflow_failure: if: ${{ failure() }} - needs: [tests, build] + needs: [check] name: Slack Notification failure runs-on: ubuntu-latest env: diff --git a/.github/workflows/ui.yml b/.github/workflows/ui.yml index a4aa3a0eda9..aff7113d0be 100644 --- a/.github/workflows/ui.yml +++ b/.github/workflows/ui.yml @@ -9,7 +9,6 @@ on: - "api-tests/**" - "dev/docs/**" - "documentation/**" - - "dashboards/**" - "managed/**" - "qan-api2/**" - "vmproxy/**" @@ -38,6 +37,17 @@ jobs: cache: yarn cache-dependency-path: ui/yarn.lock + - name: Verify plugin.json dashboard paths exist + working-directory: ${{ github.workspace }} + run: | + missing=$(jq -r '.includes[] | select(.path) | .path' ui/apps/pmm-app/src/plugin.json \ + | while read -r p; do [ -f "$p" ] || echo "$p"; done) + if [ -n "$missing" ]; then + echo "::error::plugin.json references dashboard files that do not exist:" + echo "$missing" | sed 's/^/ - /' + exit 1 + fi + - name: Check formatting run: make format-check diff --git a/build/packages/rpm/server/SPECS/percona-dashboards.spec b/build/packages/rpm/server/SPECS/percona-dashboards.spec index a894eed1f13..14221ab61e9 100644 --- a/build/packages/rpm/server/SPECS/percona-dashboards.spec +++ b/build/packages/rpm/server/SPECS/percona-dashboards.spec @@ -6,7 +6,7 @@ %global commit ad4af6808bcd361284e8eb8cd1f36b1e98e32bce %global shortcommit %(c=%{commit}; echo ${c:0:7}) %define build_timestamp %(date -u +"%y%m%d%H%M") -%define release 27 +%define release 28 %define rpm_release %{release}.%{build_timestamp}.%{shortcommit}%{?dist} %define clickhouse_datasource_version 4.19.0 @@ -46,14 +46,14 @@ using VictoriaMetrics datasource. %build node -v npm version -make -C dashboards release +cd ui && yarn install --frozen-lockfile && yarn turbo run build --filter=pmm-app %install install -d %{buildroot}%{_datadir}/%{name}/panels/pmm-app # cp -a ./dashboards/panels %{buildroot}%{_datadir}/%{name} -cp -a ./dashboards/pmm-app/dist %{buildroot}%{_datadir}/%{name}/panels/pmm-app +cp -a ./ui/apps/pmm-app/dist %{buildroot}%{_datadir}/%{name}/panels/pmm-app unzip -q %{SOURCE1} -d %{buildroot}%{_datadir}/%{name}/panels unzip -q %{SOURCE2} -d %{buildroot}%{_datadir}/%{name}/panels echo %{version} > %{buildroot}%{_datadir}/%{name}/VERSION @@ -66,6 +66,9 @@ echo %{version} > %{buildroot}%{_datadir}/%{name}/VERSION %changelog +* Thu Jul 30 2026 Fábio Silva - 3.0.0-28 +- PMM-15028 Build pmm-app from ui/apps/pmm-app (moved out of dashboards/) + * Wed Jul 15 2026 Alex Demidoff - 3.0.0-27 - PMM-15099 Bump clickhouse datasource plugin to 4.19.0 From 288a9996fb10270c220555e6263e3100f30cf7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Silva?= Date: Thu, 30 Jul 2026 18:05:38 +0000 Subject: [PATCH 04/10] Fix prettier formatting to pass ui.yml's format-check pmm-app's code (and the two AGENTS.md docs edited when it moved into ui/) had never been run through the workspace's shared Prettier config after joining ui/apps/*, so `make format-check` failed in CI. Ran `prettier --write` with the same glob the check uses; no logic changes, only formatting (mostly curried-function line breaks and operator placement, where Prettier 3.x differs from the 2.x pmm-app was previously formatted with). --- ui/AGENTS.md | 10 +- ui/apps/pmm-app/.config/jest/utils.js | 2 +- ui/apps/pmm-app/AGENTS.md | 47 +- ui/apps/pmm-app/CODE-STYLE.md | 5809 +++++++++-------- ui/apps/pmm-app/config/jest-setup.ts | 7 +- .../pmm-qan/panel/QueryAnalytics.constants.ts | 5 +- .../pmm-qan/panel/QueryAnalytics.styles.ts | 4 +- .../panel/QueryAnalytics.tools.test.ts | 3 +- .../src/pmm-qan/panel/QueryAnalytics.tools.ts | 21 +- .../src/pmm-qan/panel/QueryAnalytics.tsx | 23 +- .../panel/components/BarChart/BarChart.tsx | 29 +- .../components/BarChart/BarChart.types.ts | 6 +- .../components/BarChart/BarChart.utils.ts | 18 +- .../panel/components/Details/Details.hooks.ts | 8 +- .../components/Details/Details.messages.ts | 2 +- .../components/Details/Details.service.ts | 4 +- .../panel/components/Details/Details.tsx | 21 +- .../Details/Example/Example.test.tsx | 7 +- .../Details/Example/Example.tools.tsx | 32 +- .../components/Details/Example/Example.tsx | 6 +- .../Details/Explain/Explain.tools.ts | 20 +- .../ClassicExplain/ClassicExplain.tsx | 5 +- .../PlaceholdersForm/PlaceholdersForm.tsx | 4 +- .../PlaceholdersForm.utils.ts | 9 +- .../QueryFingerprint.test.tsx | 2 +- .../Details/Metadata/Metadata.constants.ts | 2 +- .../components/Details/Metadata/Metadata.tsx | 6 +- .../Details/Metrics/Metrics.service.ts | 8 +- .../components/Details/Metrics/Metrics.tsx | 28 +- .../Details/Metrics/Metrics.utils.ts | 10 +- .../Metrics/hooks/__mocks__/useHistogram.ts | 4 +- .../Details/Metrics/hooks/useHistogram.ts | 6 +- .../Details/Metrics/hooks/useMetricDetails.ts | 4 +- .../components/Details/Plan/Plan.hooks.ts | 4 +- .../components/Details/Plan/Plan.service.ts | 6 +- .../panel/components/Details/Plan/Plan.tsx | 6 +- .../Details/Table/TableContainer.hooks.ts | 4 +- .../Details/Table/TableContainer.tools.ts | 16 +- .../Details/Table/TableContainer.tsx | 19 +- .../Table/components/Indexes/Indexes.tsx | 4 +- .../Table/components/Status/Status.tsx | 4 +- .../components/TableCreate/TableCreate.tsx | 4 +- .../Details/TopQuery/TopQuery.test.tsx | 12 +- .../components/Details/TopQuery/TopQuery.tsx | 6 +- .../panel/components/Filters/Filters.tools.ts | 3 +- .../panel/components/Filters/Filters.tsx | 38 +- .../CheckboxGroup/CheckboxGroup.tsx | 66 +- .../components/Filters/hooks/useFilters.ts | 37 +- .../ManageColumns/ManageColumns.styles.ts | 4 +- .../ManageColumns/ManageColumns.tsx | 69 +- .../components/Overview/Overview.hooks.ts | 8 +- .../panel/components/Overview/Overview.tsx | 8 +- .../DefaultColumns/DefaultColumns.tsx | 3 +- .../MetricColumns/MetricColumns.test.tsx | 4 +- .../MetricColumns/MetricColumns.tsx | 214 +- .../Overview/components/QanTable/Table.tsx | 86 +- .../Overview/components/Search/Search.tsx | 4 +- .../pmm-qan/panel/provider/provider.tools.ts | 63 +- .../src/pmm-qan/panel/provider/provider.tsx | 167 +- .../Elements/Charts/Latency/Latency.styles.ts | 2 +- .../Elements/Charts/Latency/Latency.tsx | 20 +- .../Charts/Sparkline/Sparkline.styles.ts | 4 +- .../Charts/Sparkline/Sparkline.tools.ts | 5 +- .../Elements/Charts/Sparkline/Sparkline.tsx | 18 +- .../components/Elements/Icons/Icons.styles.ts | 7 +- .../LinkTooltip/LinkTooltip.styles.ts | 30 +- .../Elements/LinkTooltip/LinkTooltip.tsx | 8 +- .../components/Elements/Modal/Modal.styles.ts | 80 +- .../components/Elements/Modal/Modal.tsx | 4 +- .../OverflowTooltip/OverflowTooptip.tsx | 4 +- .../Elements/Overlay/Overlay.styles.ts | 2 +- .../components/Elements/Overlay/Overlay.tsx | 24 +- .../Elements/Overlay/Overlay.types.ts | 2 +- .../QueryTooltip/QueryTooltip.styles.ts | 2 +- .../Elements/QueryTooltip/QueryTooltip.tsx | 10 +- .../components/Elements/Spinner/Spinner.tsx | 4 +- .../components/Elements/Table/Table.styles.ts | 16 +- .../components/Elements/Table/Table.tsx | 11 +- .../ButtonWithSpinner.test.tsx | 16 +- .../ButtonWithSpinner/ButtonWithSpinner.tsx | 2 +- .../Form/Checkbox/Checkbox.test.tsx | 4 +- .../components/Form/Checkbox/Checkbox.tsx | 8 +- .../Form/FieldAdapters/Checkbox.tsx | 24 +- .../components/Form/FieldAdapters/Field.tsx | 54 +- .../Form/FieldAdapters/FieldAdapters.tsx | 16 +- .../Form/FormElement/FormElement.tsx | 14 +- .../Form/Radio/RadioButton.test.tsx | 12 +- .../Form/Radio/RadioButtonGroup.styles.ts | 18 +- .../Form/Radio/RadioButtonGroup.tsx | 7 +- .../components/Hightlight/Highlight.tsx | 11 +- .../src/shared/components/helpers/Helpers.tsx | 8 +- .../components/helpers/processMetrics.ts | 28 +- .../components/helpers/promises.test.tsx | 20 +- .../src/shared/components/helpers/promises.ts | 33 +- .../helpers/time-parameters-parser.ts | 9 +- .../components/helpers/validators.test.tsx | 10 +- .../shared/components/helpers/validators.ts | 31 +- .../src/shared/core/Settings.service.ts | 2 +- ui/apps/pmm-app/src/shared/core/logger.ts | 43 +- ui/apps/pmm-app/src/shared/core/theme.ts | 5 +- 100 files changed, 3803 insertions(+), 3856 deletions(-) diff --git a/ui/AGENTS.md b/ui/AGENTS.md index e307392790c..ae005472e72 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -11,12 +11,12 @@ The `/ui` directory contains the PMM web frontend — a React/TypeScript applica The UI uses a **Yarn workspaces + Turborepo** monorepo with four packages: -| Package | Path | Purpose | -| --------------- | --------------------- | ------------------------------------------------------------- | -| **pmm** | `ui/apps/pmm/` | Main PMM UI application (Vite + React) | -| **pmm-compat** | `ui/apps/pmm-compat/` | Grafana plugin for PMM ↔ Grafana integration (Webpack) | +| Package | Path | Purpose | +| --------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **pmm** | `ui/apps/pmm/` | Main PMM UI application (Vite + React) | +| **pmm-compat** | `ui/apps/pmm-compat/` | Grafana plugin for PMM ↔ Grafana integration (Webpack) | | **pmm-app** | `ui/apps/pmm-app/` | Grafana app plugin bundling PMM dashboards and the Query Analytics panel (Webpack). See [ui/apps/pmm-app/AGENTS.md](apps/pmm-app/AGENTS.md). Its `src/dashboards` is a symlink to the top-level `/dashboards` folder, the canonical source of dashboard JSON. | -| **@pmm/shared** | `ui/packages/shared/` | Shared code: cross-frame messaging, types, utilities (Rollup) | +| **@pmm/shared** | `ui/packages/shared/` | Shared code: cross-frame messaging, types, utilities (Rollup) | ### Key Technology Choices diff --git a/ui/apps/pmm-app/.config/jest/utils.js b/ui/apps/pmm-app/.config/jest/utils.js index c934289b8c0..b83aba2de3e 100644 --- a/ui/apps/pmm-app/.config/jest/utils.js +++ b/ui/apps/pmm-app/.config/jest/utils.js @@ -29,7 +29,7 @@ const grafanaESModules = [ 'get-user-locale', 'memoize', 'mimic-function', - '@wojtekmaj/date-utils' + '@wojtekmaj/date-utils', ]; module.exports = { diff --git a/ui/apps/pmm-app/AGENTS.md b/ui/apps/pmm-app/AGENTS.md index 350ca155525..767506b0bab 100644 --- a/ui/apps/pmm-app/AGENTS.md +++ b/ui/apps/pmm-app/AGENTS.md @@ -29,20 +29,20 @@ Build (webpack) → dist/ ### Key Technology Choices -| Technology | Role | -|------------|------| -| **TypeScript** | Type-safe development | -| **React 18** | UI framework | -| **Webpack** | Build tooling (Grafana plugin scaffolding) | -| **Yarn 1.x** | Package manager, hoisted from the `ui/` workspace root | -| **SCSS / LESS** | Styling | -| **@grafana/data, @grafana/ui, @grafana/runtime** | Grafana plugin SDK (`>=11.x.x`) | -| **Ant Design** | Additional UI components (QAN panel) | -| **axios** | HTTP client for QAN API calls | -| **react-table** | Table rendering in QAN Overview | -| **d3** | Data visualization | -| **Jest 29** | Unit testing (`@swc/jest`, `jest-environment-jsdom`) | -| **chokidar** | Dashboard JSON file watcher for local dev (`scripts/watch-dashboards.mjs`) | +| Technology | Role | +| ------------------------------------------------ | -------------------------------------------------------------------------- | +| **TypeScript** | Type-safe development | +| **React 18** | UI framework | +| **Webpack** | Build tooling (Grafana plugin scaffolding) | +| **Yarn 1.x** | Package manager, hoisted from the `ui/` workspace root | +| **SCSS / LESS** | Styling | +| **@grafana/data, @grafana/ui, @grafana/runtime** | Grafana plugin SDK (`>=11.x.x`) | +| **Ant Design** | Additional UI components (QAN panel) | +| **axios** | HTTP client for QAN API calls | +| **react-table** | Table rendering in QAN Overview | +| **d3** | Data visualization | +| **Jest 29** | Unit testing (`@swc/jest`, `jest-environment-jsdom`) | +| **chokidar** | Dashboard JSON file watcher for local dev (`scripts/watch-dashboards.mjs`) | ## QAN Panel @@ -50,18 +50,19 @@ The Query Analytics panel lives in `src/pmm-qan/` and is registered as a `PanelP ### Key Sub-Components -| Component | Path | Purpose | -|-----------|------|---------| -| **QueryAnalytics** | `pmm-qan/panel/QueryAnalytics.tsx` | Root panel component | -| **Overview** | `pmm-qan/panel/components/Overview/` | Main query table with sortable metrics columns | -| **Details** | `pmm-qan/panel/components/Details/` | Query detail view: Explain, Metrics, Metadata, Table | -| **Filters** | `pmm-qan/panel/components/Filters/` | Filter sidebar (dimension, value filtering) | -| **BarChart** | `pmm-qan/panel/components/BarChart/` | Time-distribution bar chart | -| **ManageColumns** | `pmm-qan/panel/components/ManageColumns/` | Column visibility picker | +| Component | Path | Purpose | +| ------------------ | ----------------------------------------- | ---------------------------------------------------- | +| **QueryAnalytics** | `pmm-qan/panel/QueryAnalytics.tsx` | Root panel component | +| **Overview** | `pmm-qan/panel/components/Overview/` | Main query table with sortable metrics columns | +| **Details** | `pmm-qan/panel/components/Details/` | Query detail view: Explain, Metrics, Metadata, Table | +| **Filters** | `pmm-qan/panel/components/Filters/` | Filter sidebar (dimension, value filtering) | +| **BarChart** | `pmm-qan/panel/components/BarChart/` | Time-distribution bar chart | +| **ManageColumns** | `pmm-qan/panel/components/ManageColumns/` | Column visibility picker | ### Shared Code `src/shared/` contains reusable code across the QAN panel: + - `components/` — common UI elements (Table, Modal, Charts, Icons, Form controls) - `components/helpers/` — humanization, formatting, validators - `components/hooks/` — shared React hooks (e.g., window size) @@ -70,6 +71,7 @@ The Query Analytics panel lives in `src/pmm-qan/` and is registered as a `PanelP ## Patterns and Conventions ### Do + - Co-locate test files next to components (`*.test.tsx`) - Use `@testing-library/react` for component tests - Use `@grafana/data` and `@grafana/ui` APIs for Grafana integration @@ -77,6 +79,7 @@ The Query Analytics panel lives in `src/pmm-qan/` and is registered as a `PanelP - Follow the Grafana plugin SDK conventions for panel lifecycle ### Don't + - Don't modify files under `.config/` — they are scaffolded by `@grafana/create-plugin` and carry "do not edit" warnings - Don't introduce new state management libraries — use React state/context as in existing QAN code - Don't duplicate dashboard JSON inside `src/` — the canonical source is the top-level `dashboards/` folder, reached through the `src/dashboards` symlink diff --git a/ui/apps/pmm-app/CODE-STYLE.md b/ui/apps/pmm-app/CODE-STYLE.md index 9777ec943b0..461e6372e71 100644 --- a/ui/apps/pmm-app/CODE-STYLE.md +++ b/ui/apps/pmm-app/CODE-STYLE.md @@ -38,3592 +38,3672 @@ ## Types - - - [1.1](#types--primitives) **Primitives**: When you access a primitive type you work directly on its value. + - - `string` - - `number` - - `boolean` - - `null` - - `undefined` - - `symbol` - - `bigint` +- [1.1](#types--primitives) **Primitives**: When you access a primitive type you work directly on its value. - ```javascript - const foo = 1; - let bar = foo; + - `string` + - `number` + - `boolean` + - `null` + - `undefined` + - `symbol` + - `bigint` - bar = 9; + ```javascript + const foo = 1; + let bar = foo; + + bar = 9; + + console.log(foo, bar); // => 1, 9 + ``` - console.log(foo, bar); // => 1, 9 - ``` + - Symbols and BigInts cannot be faithfully polyfilled, so they should not be used when targeting browsers/environments that don’t support them natively. - - Symbols and BigInts cannot be faithfully polyfilled, so they should not be used when targeting browsers/environments that don’t support them natively. + - - - [1.2](#types--complex) **Complex**: When you access a complex type you work on a reference to its value. +- [1.2](#types--complex) **Complex**: When you access a complex type you work on a reference to its value. - - `object` - - `array` - - `function` + - `object` + - `array` + - `function` - ```javascript - const foo = [1, 2]; - const bar = foo; + ```javascript + const foo = [1, 2]; + const bar = foo; - bar[0] = 9; + bar[0] = 9; - console.log(foo[0], bar[0]); // => 9, 9 - ``` + console.log(foo[0], bar[0]); // => 9, 9 + ``` **[⬆ back to top](#table-of-contents)** ## References - - - [2.1](#references--prefer-const) Use `const` for all of your references; avoid using `var`. eslint: [`prefer-const`](https://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](https://eslint.org/docs/rules/no-const-assign.html) + - > Why? This ensures that you can’t reassign your references, which can lead to bugs and difficult to comprehend code. +- [2.1](#references--prefer-const) Use `const` for all of your references; avoid using `var`. eslint: [`prefer-const`](https://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](https://eslint.org/docs/rules/no-const-assign.html) - ```javascript - // bad - var a = 1; - var b = 2; + > Why? This ensures that you can’t reassign your references, which can lead to bugs and difficult to comprehend code. - // good - const a = 1; - const b = 2; - ``` + ```javascript + // bad + var a = 1; + var b = 2; - - - [2.2](#references--disallow-var) If you must reassign references, use `let` instead of `var`. eslint: [`no-var`](https://eslint.org/docs/rules/no-var.html) + // good + const a = 1; + const b = 2; + ``` - > Why? `let` is block-scoped rather than function-scoped like `var`. + - ```javascript - // bad - var count = 1; - if (true) { - count += 1; - } +- [2.2](#references--disallow-var) If you must reassign references, use `let` instead of `var`. eslint: [`no-var`](https://eslint.org/docs/rules/no-var.html) - // good, use the let. - let count = 1; - if (true) { - count += 1; - } - ``` + > Why? `let` is block-scoped rather than function-scoped like `var`. - - - [2.3](#references--block-scope) Note that both `let` and `const` are block-scoped. + ```javascript + // bad + var count = 1; + if (true) { + count += 1; + } - ```javascript - // const and let only exist in the blocks they are defined in. - { - let a = 1; - const b = 1; - } - console.log(a); // ReferenceError - console.log(b); // ReferenceError - ``` + // good, use the let. + let count = 1; + if (true) { + count += 1; + } + ``` -**[⬆ back to top](#table-of-contents)** + -## Objects +- [2.3](#references--block-scope) Note that both `let` and `const` are block-scoped. - - - [3.1](#objects--no-new) Use the literal syntax for object creation. eslint: [`no-new-object`](https://eslint.org/docs/rules/no-new-object.html) + ```javascript + // const and let only exist in the blocks they are defined in. + { + let a = 1; + const b = 1; + } + console.log(a); // ReferenceError + console.log(b); // ReferenceError + ``` - ```javascript - // bad - const item = new Object(); +**[⬆ back to top](#table-of-contents)** - // good - const item = {}; - ``` +## Objects - - - [3.2](#es6-computed-properties) Use computed property names when creating objects with dynamic property names. + - > Why? They allow you to define all the properties of an object in one place. +- [3.1](#objects--no-new) Use the literal syntax for object creation. eslint: [`no-new-object`](https://eslint.org/docs/rules/no-new-object.html) - ```javascript + ```javascript + // bad + const item = new Object(); - function getKey(k) { - return `a key named ${k}`; - } + // good + const item = {}; + ``` - // bad - const obj = { - id: 5, - name: 'San Francisco', - }; - obj[getKey('enabled')] = true; + - // good - const obj = { - id: 5, - name: 'San Francisco', - [getKey('enabled')]: true, - }; - ``` +- [3.2](#es6-computed-properties) Use computed property names when creating objects with dynamic property names. - - - [3.3](#es6-object-shorthand) Use object method shorthand. eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html) + > Why? They allow you to define all the properties of an object in one place. - ```javascript - // bad - const atom = { - value: 1, + ```javascript + function getKey(k) { + return `a key named ${k}`; + } - addValue: function (value) { - return atom.value + value; - }, - }; + // bad + const obj = { + id: 5, + name: 'San Francisco', + }; + obj[getKey('enabled')] = true; + + // good + const obj = { + id: 5, + name: 'San Francisco', + [getKey('enabled')]: true, + }; + ``` - // good - const atom = { - value: 1, + - addValue(value) { - return atom.value + value; - }, - }; - ``` +- [3.3](#es6-object-shorthand) Use object method shorthand. eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html) - - - [3.4](#es6-object-concise) Use property value shorthand. eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html) + ```javascript + // bad + const atom = { + value: 1, + + addValue: function (value) { + return atom.value + value; + }, + }; + + // good + const atom = { + value: 1, + + addValue(value) { + return atom.value + value; + }, + }; + ``` - > Why? It is shorter and descriptive. + - ```javascript - const lukeSkywalker = 'Luke Skywalker'; +- [3.4](#es6-object-concise) Use property value shorthand. eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html) - // bad - const obj = { - lukeSkywalker: lukeSkywalker, - }; + > Why? It is shorter and descriptive. - // good - const obj = { - lukeSkywalker, - }; - ``` + ```javascript + const lukeSkywalker = 'Luke Skywalker'; - - - [3.5](#objects--grouped-shorthand) Group your shorthand properties at the beginning of your object declaration. + // bad + const obj = { + lukeSkywalker: lukeSkywalker, + }; - > Why? It’s easier to tell which properties are using the shorthand. + // good + const obj = { + lukeSkywalker, + }; + ``` - ```javascript - const anakinSkywalker = 'Anakin Skywalker'; - const lukeSkywalker = 'Luke Skywalker'; + - // bad - const obj = { - episodeOne: 1, - twoJediWalkIntoACantina: 2, - lukeSkywalker, - episodeThree: 3, - mayTheFourth: 4, - anakinSkywalker, - }; +- [3.5](#objects--grouped-shorthand) Group your shorthand properties at the beginning of your object declaration. - // good - const obj = { - lukeSkywalker, - anakinSkywalker, - episodeOne: 1, - twoJediWalkIntoACantina: 2, - episodeThree: 3, - mayTheFourth: 4, - }; - ``` + > Why? It’s easier to tell which properties are using the shorthand. - - - [3.6](#objects--quoted-props) Only quote properties that are invalid identifiers. eslint: [`quote-props`](https://eslint.org/docs/rules/quote-props.html) + ```javascript + const anakinSkywalker = 'Anakin Skywalker'; + const lukeSkywalker = 'Luke Skywalker'; + + // bad + const obj = { + episodeOne: 1, + twoJediWalkIntoACantina: 2, + lukeSkywalker, + episodeThree: 3, + mayTheFourth: 4, + anakinSkywalker, + }; + + // good + const obj = { + lukeSkywalker, + anakinSkywalker, + episodeOne: 1, + twoJediWalkIntoACantina: 2, + episodeThree: 3, + mayTheFourth: 4, + }; + ``` - > Why? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines. + - ```javascript - // bad - const bad = { - 'foo': 3, - 'bar': 4, - 'data-blah': 5, - }; +- [3.6](#objects--quoted-props) Only quote properties that are invalid identifiers. eslint: [`quote-props`](https://eslint.org/docs/rules/quote-props.html) - // good - const good = { - foo: 3, - bar: 4, - 'data-blah': 5, - }; - ``` + > Why? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines. + + ```javascript + // bad + const bad = { + foo: 3, + bar: 4, + 'data-blah': 5, + }; + + // good + const good = { + foo: 3, + bar: 4, + 'data-blah': 5, + }; + ``` - - - [3.7](#objects--prototype-builtins) Do not call `Object.prototype` methods directly, such as `hasOwnProperty`, `propertyIsEnumerable`, and `isPrototypeOf`. eslint: [`no-prototype-builtins`](https://eslint.org/docs/rules/no-prototype-builtins) + - > Why? These methods may be shadowed by properties on the object in question - consider `{ hasOwnProperty: false }` - or, the object may be a null object (`Object.create(null)`). +- [3.7](#objects--prototype-builtins) Do not call `Object.prototype` methods directly, such as `hasOwnProperty`, `propertyIsEnumerable`, and `isPrototypeOf`. eslint: [`no-prototype-builtins`](https://eslint.org/docs/rules/no-prototype-builtins) - ```javascript - // bad - console.log(object.hasOwnProperty(key)); + > Why? These methods may be shadowed by properties on the object in question - consider `{ hasOwnProperty: false }` - or, the object may be a null object (`Object.create(null)`). - // good - console.log(Object.prototype.hasOwnProperty.call(object, key)); + ```javascript + // bad + console.log(object.hasOwnProperty(key)); + + // good + console.log(Object.prototype.hasOwnProperty.call(object, key)); + + // best + const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope. + console.log(has.call(object, key)); + /* or */ + import has from 'has'; // https://www.npmjs.com/package/has + console.log(has(object, key)); + ``` - // best - const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope. - console.log(has.call(object, key)); - /* or */ - import has from 'has'; // https://www.npmjs.com/package/has - console.log(has(object, key)); - ``` + - - - [3.8](#objects--rest-spread) Prefer the object spread operator over [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted. +- [3.8](#objects--rest-spread) Prefer the object spread operator over [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted. - ```javascript - // very bad - const original = { a: 1, b: 2 }; - const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ - delete copy.a; // so does this + ```javascript + // very bad + const original = { a: 1, b: 2 }; + const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ + delete copy.a; // so does this - // bad - const original = { a: 1, b: 2 }; - const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } + // bad + const original = { a: 1, b: 2 }; + const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } - // good - const original = { a: 1, b: 2 }; - const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } + // good + const original = { a: 1, b: 2 }; + const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } - const { a, ...noA } = copy; // noA => { b: 2, c: 3 } - ``` + const { a, ...noA } = copy; // noA => { b: 2, c: 3 } + ``` **[⬆ back to top](#table-of-contents)** ## Arrays - - - [4.1](#arrays--literals) Use the literal syntax for array creation. eslint: [`no-array-constructor`](https://eslint.org/docs/rules/no-array-constructor.html) + - ```javascript - // bad - const items = new Array(); +- [4.1](#arrays--literals) Use the literal syntax for array creation. eslint: [`no-array-constructor`](https://eslint.org/docs/rules/no-array-constructor.html) - // good - const items = []; - ``` + ```javascript + // bad + const items = new Array(); - - - [4.2](#arrays--push) Use [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push) instead of direct assignment to add items to an array. + // good + const items = []; + ``` - ```javascript - const someStack = []; + - // bad - someStack[someStack.length] = 'abracadabra'; +- [4.2](#arrays--push) Use [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push) instead of direct assignment to add items to an array. - // good - someStack.push('abracadabra'); - ``` + ```javascript + const someStack = []; - - - [4.3](#es6-array-spreads) Use array spreads `...` to copy arrays. + // bad + someStack[someStack.length] = 'abracadabra'; - ```javascript - // bad - const len = items.length; - const itemsCopy = []; - let i; + // good + someStack.push('abracadabra'); + ``` - for (i = 0; i < len; i += 1) { - itemsCopy[i] = items[i]; - } + - // good - const itemsCopy = [...items]; - ``` +- [4.3](#es6-array-spreads) Use array spreads `...` to copy arrays. - - - - [4.4](#arrays--from-iterable) To convert an iterable object to an array, use spreads `...` instead of [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from). + ```javascript + // bad + const len = items.length; + const itemsCopy = []; + let i; - ```javascript - const foo = document.querySelectorAll('.foo'); + for (i = 0; i < len; i += 1) { + itemsCopy[i] = items[i]; + } - // good - const nodes = Array.from(foo); + // good + const itemsCopy = [...items]; + ``` - // best - const nodes = [...foo]; - ``` + + - - - [4.5](#arrays--from-array-like) Use [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) for converting an array-like object to an array. +- [4.4](#arrays--from-iterable) To convert an iterable object to an array, use spreads `...` instead of [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from). - ```javascript - const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; + ```javascript + const foo = document.querySelectorAll('.foo'); - // bad - const arr = Array.prototype.slice.call(arrLike); + // good + const nodes = Array.from(foo); - // good - const arr = Array.from(arrLike); - ``` + // best + const nodes = [...foo]; + ``` - - - [4.6](#arrays--mapping) Use [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) instead of spread `...` for mapping over iterables, because it avoids creating an intermediate array. + - ```javascript - // bad - const baz = [...foo].map(bar); +- [4.5](#arrays--from-array-like) Use [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) for converting an array-like object to an array. - // good - const baz = Array.from(foo, bar); - ``` + ```javascript + const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; - - - [4.7](#arrays--callback-return) Use return statements in array method callbacks. It’s ok to omit the return if the function body consists of a single statement returning an expression without side effects, following [8.2](#arrows--implicit-return). eslint: [`array-callback-return`](https://eslint.org/docs/rules/array-callback-return) + // bad + const arr = Array.prototype.slice.call(arrLike); - ```javascript - // good - [1, 2, 3].map((x) => { - const y = x + 1; - return x * y; - }); + // good + const arr = Array.from(arrLike); + ``` - // good - [1, 2, 3].map((x) => x + 1); + - // bad - no returned value means `acc` becomes undefined after the first iteration - [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { - const flatten = acc.concat(item); - }); +- [4.6](#arrays--mapping) Use [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) instead of spread `...` for mapping over iterables, because it avoids creating an intermediate array. - // good - [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { - const flatten = acc.concat(item); - return flatten; - }); + ```javascript + // bad + const baz = [...foo].map(bar); - // bad - inbox.filter((msg) => { - const { subject, author } = msg; - if (subject === 'Mockingbird') { - return author === 'Harper Lee'; - } else { - return false; - } - }); + // good + const baz = Array.from(foo, bar); + ``` - // good - inbox.filter((msg) => { - const { subject, author } = msg; - if (subject === 'Mockingbird') { - return author === 'Harper Lee'; - } + +- [4.7](#arrays--callback-return) Use return statements in array method callbacks. It’s ok to omit the return if the function body consists of a single statement returning an expression without side effects, following [8.2](#arrows--implicit-return). eslint: [`array-callback-return`](https://eslint.org/docs/rules/array-callback-return) + + ```javascript + // good + [1, 2, 3].map((x) => { + const y = x + 1; + return x * y; + }); + + // good + [1, 2, 3].map((x) => x + 1); + + // bad - no returned value means `acc` becomes undefined after the first iteration + [ + [0, 1], + [2, 3], + [4, 5], + ].reduce((acc, item, index) => { + const flatten = acc.concat(item); + }); + + // good + [ + [0, 1], + [2, 3], + [4, 5], + ].reduce((acc, item, index) => { + const flatten = acc.concat(item); + return flatten; + }); + + // bad + inbox.filter((msg) => { + const { subject, author } = msg; + if (subject === 'Mockingbird') { + return author === 'Harper Lee'; + } else { return false; - }); - ``` + } + }); + + // good + inbox.filter((msg) => { + const { subject, author } = msg; + if (subject === 'Mockingbird') { + return author === 'Harper Lee'; + } + + return false; + }); + ``` - - - [4.8](#arrays--bracket-newline) Use line breaks after open and before close array brackets if an array has multiple lines + - ```javascript - // bad - const arr = [ - [0, 1], [2, 3], [4, 5], - ]; +- [4.8](#arrays--bracket-newline) Use line breaks after open and before close array brackets if an array has multiple lines - const objectInArray = [{ + ```javascript + // bad + const arr = [ + [0, 1], + [2, 3], + [4, 5], + ]; + + const objectInArray = [ + { id: 1, - }, { + }, + { id: 2, - }]; - - const numberInArray = [ - 1, 2, - ]; - - // good - const arr = [[0, 1], [2, 3], [4, 5]]; - - const objectInArray = [ - { - id: 1, - }, - { - id: 2, - }, - ]; - - const numberInArray = [ - 1, - 2, - ]; - ``` + }, + ]; -**[⬆ back to top](#table-of-contents)** + const numberInArray = [1, 2]; -## Destructuring + // good + const arr = [ + [0, 1], + [2, 3], + [4, 5], + ]; - - - [5.1](#destructuring--object) Use object destructuring when accessing and using multiple properties of an object. eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring) + const objectInArray = [ + { + id: 1, + }, + { + id: 2, + }, + ]; - > Why? Destructuring saves you from creating temporary references for those properties. + const numberInArray = [1, 2]; + ``` - ```javascript - // bad - function getFullName(user) { - const firstName = user.firstName; - const lastName = user.lastName; +**[⬆ back to top](#table-of-contents)** - return `${firstName} ${lastName}`; - } +## Destructuring - // good - function getFullName(user) { - const { firstName, lastName } = user; - return `${firstName} ${lastName}`; - } + - // best - function getFullName({ firstName, lastName }) { - return `${firstName} ${lastName}`; - } - ``` +- [5.1](#destructuring--object) Use object destructuring when accessing and using multiple properties of an object. eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring) - - - [5.2](#destructuring--array) Use array destructuring. eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring) + > Why? Destructuring saves you from creating temporary references for those properties. - ```javascript - const arr = [1, 2, 3, 4]; + ```javascript + // bad + function getFullName(user) { + const firstName = user.firstName; + const lastName = user.lastName; - // bad - const first = arr[0]; - const second = arr[1]; + return `${firstName} ${lastName}`; + } - // good - const [first, second] = arr; - ``` + // good + function getFullName(user) { + const { firstName, lastName } = user; + return `${firstName} ${lastName}`; + } - - - [5.3](#destructuring--object-over-array) Use object destructuring for multiple return values, not array destructuring. + // best + function getFullName({ firstName, lastName }) { + return `${firstName} ${lastName}`; + } + ``` - > Why? You can add new properties over time or change the order of things without breaking call sites. + - ```javascript - // bad - function processInput(input) { - // then a miracle occurs - return [left, right, top, bottom]; - } +- [5.2](#destructuring--array) Use array destructuring. eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring) - // the caller needs to think about the order of return data - const [left, __, top] = processInput(input); + ```javascript + const arr = [1, 2, 3, 4]; - // good - function processInput(input) { - // then a miracle occurs - return { left, right, top, bottom }; - } + // bad + const first = arr[0]; + const second = arr[1]; - // the caller selects only the data they need - const { left, top } = processInput(input); - ``` + // good + const [first, second] = arr; + ``` -**[⬆ back to top](#table-of-contents)** + -## Strings +- [5.3](#destructuring--object-over-array) Use object destructuring for multiple return values, not array destructuring. - - - [6.1](#strings--quotes) Use single quotes `''` for strings. eslint: [`quotes`](https://eslint.org/docs/rules/quotes.html) + > Why? You can add new properties over time or change the order of things without breaking call sites. - ```javascript - // bad - const name = "Capt. Janeway"; + ```javascript + // bad + function processInput(input) { + // then a miracle occurs + return [left, right, top, bottom]; + } - // bad - template literals should contain interpolation or newlines - const name = `Capt. Janeway`; + // the caller needs to think about the order of return data + const [left, __, top] = processInput(input); - // good - const name = 'Capt. Janeway'; - ``` + // good + function processInput(input) { + // then a miracle occurs + return { left, right, top, bottom }; + } - - - [6.2](#strings--line-length) Strings that cause the line to go over 100 characters should not be written across multiple lines using string concatenation. + // the caller selects only the data they need + const { left, top } = processInput(input); + ``` - > Why? Broken strings are painful to work with and make code less searchable. +**[⬆ back to top](#table-of-contents)** - ```javascript - // bad - const errorMessage = 'This is a super long error that was thrown because \ - of Batman. When you stop to think about how Batman had anything to do \ - with this, you would get nowhere \ - fast.'; +## Strings - // bad - const errorMessage = 'This is a super long error that was thrown because ' + - 'of Batman. When you stop to think about how Batman had anything to do ' + - 'with this, you would get nowhere fast.'; + - // good - const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; - ``` +- [6.1](#strings--quotes) Use single quotes `''` for strings. eslint: [`quotes`](https://eslint.org/docs/rules/quotes.html) - - - [6.3](#es6-template-literals) When programmatically building up strings, use template strings instead of concatenation. eslint: [`prefer-template`](https://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](https://eslint.org/docs/rules/template-curly-spacing) + ```javascript + // bad + const name = 'Capt. Janeway'; - > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. + // bad - template literals should contain interpolation or newlines + const name = `Capt. Janeway`; - ```javascript - // bad - function sayHi(name) { - return 'How are you, ' + name + '?'; - } + // good + const name = 'Capt. Janeway'; + ``` - // bad - function sayHi(name) { - return ['How are you, ', name, '?'].join(); - } + - // bad - function sayHi(name) { - return `How are you, ${ name }?`; - } +- [6.2](#strings--line-length) Strings that cause the line to go over 100 characters should not be written across multiple lines using string concatenation. - // good - function sayHi(name) { - return `How are you, ${name}?`; - } - ``` + > Why? Broken strings are painful to work with and make code less searchable. - - - [6.4](#strings--eval) Never use `eval()` on a string, it opens too many vulnerabilities. eslint: [`no-eval`](https://eslint.org/docs/rules/no-eval) + ```javascript + // bad + const errorMessage = + 'This is a super long error that was thrown because \ + of Batman. When you stop to think about how Batman had anything to do \ + with this, you would get nowhere \ + fast.'; + + // bad + const errorMessage = + 'This is a super long error that was thrown because ' + + 'of Batman. When you stop to think about how Batman had anything to do ' + + 'with this, you would get nowhere fast.'; + + // good + const errorMessage = + 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; + ``` - - - [6.5](#strings--escaping) Do not unnecessarily escape characters in strings. eslint: [`no-useless-escape`](https://eslint.org/docs/rules/no-useless-escape) + - > Why? Backslashes harm readability, thus they should only be present when necessary. +- [6.3](#es6-template-literals) When programmatically building up strings, use template strings instead of concatenation. eslint: [`prefer-template`](https://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](https://eslint.org/docs/rules/template-curly-spacing) - ```javascript - // bad - const foo = '\'this\' \i\s \"quoted\"'; + > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. - // good - const foo = '\'this\' is "quoted"'; - const foo = `my name is '${name}'`; - ``` + ```javascript + // bad + function sayHi(name) { + return 'How are you, ' + name + '?'; + } -**[⬆ back to top](#table-of-contents)** + // bad + function sayHi(name) { + return ['How are you, ', name, '?'].join(); + } -## Functions + // bad + function sayHi(name) { + return `How are you, ${name}?`; + } - - - [7.1](#functions--declarations) Use named function expressions instead of function declarations. eslint: [`func-style`](https://eslint.org/docs/rules/func-style) + // good + function sayHi(name) { + return `How are you, ${name}?`; + } + ``` - > Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error’s call stack. ([Discussion](https://github.com/airbnb/javascript/issues/794)) + - ```javascript - // bad - function foo() { - // ... - } +- [6.4](#strings--eval) Never use `eval()` on a string, it opens too many vulnerabilities. eslint: [`no-eval`](https://eslint.org/docs/rules/no-eval) - // bad - const foo = function () { - // ... - }; + - // good - // lexical name distinguished from the variable-referenced invocation(s) - const short = function longUniqueMoreDescriptiveLexicalFoo() { - // ... - }; - ``` +- [6.5](#strings--escaping) Do not unnecessarily escape characters in strings. eslint: [`no-useless-escape`](https://eslint.org/docs/rules/no-useless-escape) - - - [7.2](#functions--iife) Wrap immediately invoked function expressions in parentheses. eslint: [`wrap-iife`](https://eslint.org/docs/rules/wrap-iife.html) + > Why? Backslashes harm readability, thus they should only be present when necessary. - > Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE. + ```javascript + // bad + const foo = '\'this\' \i\s \"quoted\"'; - ```javascript - // immediately-invoked function expression (IIFE) - (function () { - console.log('Welcome to the Internet. Please follow me.'); - }()); - ``` + // good + const foo = '\'this\' is "quoted"'; + const foo = `my name is '${name}'`; + ``` - - - [7.3](#functions--in-blocks) Never declare a function in a non-function block (`if`, `while`, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. eslint: [`no-loop-func`](https://eslint.org/docs/rules/no-loop-func.html) +**[⬆ back to top](#table-of-contents)** - - - [7.4](#functions--note-on-blocks) **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. +## Functions - ```javascript - // bad - if (currentUser) { - function test() { - console.log('Nope.'); - } - } + - // good - let test; - if (currentUser) { - test = () => { - console.log('Yup.'); - }; - } - ``` +- [7.1](#functions--declarations) Use named function expressions instead of function declarations. eslint: [`func-style`](https://eslint.org/docs/rules/func-style) - - - [7.5](#functions--arguments-shadow) Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. + > Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error’s call stack. ([Discussion](https://github.com/airbnb/javascript/issues/794)) - ```javascript - // bad - function foo(name, options, arguments) { - // ... - } + ```javascript + // bad + function foo() { + // ... + } - // good - function foo(name, options, args) { - // ... - } - ``` + // bad + const foo = function () { + // ... + }; - - - [7.6](#es6-rest) Never use `arguments`, opt to use rest syntax `...` instead. eslint: [`prefer-rest-params`](https://eslint.org/docs/rules/prefer-rest-params) + // good + // lexical name distinguished from the variable-referenced invocation(s) + const short = function longUniqueMoreDescriptiveLexicalFoo() { + // ... + }; + ``` - > Why? `...` is explicit about which arguments you want pulled. Plus, rest arguments are a real Array, and not merely Array-like like `arguments`. + - ```javascript - // bad - function concatenateAll() { - const args = Array.prototype.slice.call(arguments); - return args.join(''); - } +- [7.2](#functions--iife) Wrap immediately invoked function expressions in parentheses. eslint: [`wrap-iife`](https://eslint.org/docs/rules/wrap-iife.html) - // good - function concatenateAll(...args) { - return args.join(''); - } - ``` - - - - [7.7](#es6-default-parameters) Use default parameter syntax rather than mutating function arguments. - - ```javascript - // really bad - function handleThings(opts) { - // No! We shouldn’t mutate function arguments. - // Double bad: if opts is falsy it'll be set to an object which may - // be what you want but it can introduce subtle bugs. - opts = opts || {}; - // ... - } + > Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE. - // still bad - function handleThings(opts) { - if (opts === void 0) { - opts = {}; - } - // ... - } + ```javascript + // immediately-invoked function expression (IIFE) + (function () { + console.log('Welcome to the Internet. Please follow me.'); + })(); + ``` - // good - function handleThings(opts = {}) { - // ... - } - ``` + - - - [7.8](#functions--default-side-effects) Avoid side effects with default parameters. +- [7.3](#functions--in-blocks) Never declare a function in a non-function block (`if`, `while`, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. eslint: [`no-loop-func`](https://eslint.org/docs/rules/no-loop-func.html) - > Why? They are confusing to reason about. + - ```javascript - var b = 1; - // bad - function count(a = b++) { - console.log(a); - } - count(); // 1 - count(); // 2 - count(3); // 3 - count(); // 3 - ``` - - - - [7.9](#functions--defaults-last) Always put default parameters last. - - ```javascript - // bad - function handleThings(opts = {}, name) { - // ... - } +- [7.4](#functions--note-on-blocks) **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. - // good - function handleThings(name, opts = {}) { - // ... + ```javascript + // bad + if (currentUser) { + function test() { + console.log('Nope.'); } - ``` - - - - [7.10](#functions--constructor) Never use the Function constructor to create a new function. eslint: [`no-new-func`](https://eslint.org/docs/rules/no-new-func) + } - > Why? Creating a function in this way evaluates a string similarly to `eval()`, which opens vulnerabilities. + // good + let test; + if (currentUser) { + test = () => { + console.log('Yup.'); + }; + } + ``` - ```javascript - // bad - var add = new Function('a', 'b', 'return a + b'); + - // still bad - var subtract = Function('a', 'b', 'return a - b'); - ``` +- [7.5](#functions--arguments-shadow) Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. - - - [7.11](#functions--signature-spacing) Spacing in a function signature. eslint: [`space-before-function-paren`](https://eslint.org/docs/rules/space-before-function-paren) [`space-before-blocks`](https://eslint.org/docs/rules/space-before-blocks) + ```javascript + // bad + function foo(name, options, arguments) { + // ... + } - > Why? Consistency is good, and you shouldn’t have to add or remove a space when adding or removing a name. + // good + function foo(name, options, args) { + // ... + } + ``` - ```javascript - // bad - const f = function(){}; - const g = function (){}; - const h = function() {}; + - // good - const x = function () {}; - const y = function a() {}; - ``` +- [7.6](#es6-rest) Never use `arguments`, opt to use rest syntax `...` instead. eslint: [`prefer-rest-params`](https://eslint.org/docs/rules/prefer-rest-params) - - - [7.12](#functions--mutate-params) Never mutate parameters. eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html) + > Why? `...` is explicit about which arguments you want pulled. Plus, rest arguments are a real Array, and not merely Array-like like `arguments`. - > Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller. + ```javascript + // bad + function concatenateAll() { + const args = Array.prototype.slice.call(arguments); + return args.join(''); + } - ```javascript - // bad - function f1(obj) { - obj.key = 1; - } + // good + function concatenateAll(...args) { + return args.join(''); + } + ``` - // good - function f2(obj) { - const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; - } - ``` + - - - [7.13](#functions--reassign-params) Never reassign parameters. eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html) +- [7.7](#es6-default-parameters) Use default parameter syntax rather than mutating function arguments. - > Why? Reassigning parameters can lead to unexpected behavior, especially when accessing the `arguments` object. It can also cause optimization issues, especially in V8. + ```javascript + // really bad + function handleThings(opts) { + // No! We shouldn’t mutate function arguments. + // Double bad: if opts is falsy it'll be set to an object which may + // be what you want but it can introduce subtle bugs. + opts = opts || {}; + // ... + } - ```javascript - // bad - function f1(a) { - a = 1; - // ... + // still bad + function handleThings(opts) { + if (opts === void 0) { + opts = {}; } + // ... + } - function f2(a) { - if (!a) { a = 1; } - // ... - } + // good + function handleThings(opts = {}) { + // ... + } + ``` - // good - function f3(a) { - const b = a || 1; - // ... - } + - function f4(a = 1) { - // ... - } - ``` +- [7.8](#functions--default-side-effects) Avoid side effects with default parameters. - - - [7.14](#functions--spread-vs-apply) Prefer the use of the spread operator `...` to call variadic functions. eslint: [`prefer-spread`](https://eslint.org/docs/rules/prefer-spread) + > Why? They are confusing to reason about. - > Why? It’s cleaner, you don’t need to supply a context, and you can not easily compose `new` with `apply`. + ```javascript + var b = 1; + // bad + function count(a = b++) { + console.log(a); + } + count(); // 1 + count(); // 2 + count(3); // 3 + count(); // 3 + ``` - ```javascript - // bad - const x = [1, 2, 3, 4, 5]; - console.log.apply(console, x); + - // good - const x = [1, 2, 3, 4, 5]; - console.log(...x); +- [7.9](#functions--defaults-last) Always put default parameters last. - // bad - new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5])); + ```javascript + // bad + function handleThings(opts = {}, name) { + // ... + } - // good - new Date(...[2016, 8, 5]); - ``` + // good + function handleThings(name, opts = {}) { + // ... + } + ``` - - - [7.15](#functions--signature-invocation-indentation) Functions with multiline signatures, or invocations, should be indented just like every other multiline list in this guide: with each item on a line by itself, with a trailing comma on the last item. eslint: [`function-paren-newline`](https://eslint.org/docs/rules/function-paren-newline) + - ```javascript - // bad - function foo(bar, - baz, - quux) { - // ... - } +- [7.10](#functions--constructor) Never use the Function constructor to create a new function. eslint: [`no-new-func`](https://eslint.org/docs/rules/no-new-func) - // good - function foo( - bar, - baz, - quux, - ) { - // ... - } + > Why? Creating a function in this way evaluates a string similarly to `eval()`, which opens vulnerabilities. - // bad - console.log(foo, - bar, - baz); + ```javascript + // bad + var add = new Function('a', 'b', 'return a + b'); - // good - console.log( - foo, - bar, - baz, - ); - ``` + // still bad + var subtract = Function('a', 'b', 'return a - b'); + ``` -**[⬆ back to top](#table-of-contents)** + -## Arrow Functions +- [7.11](#functions--signature-spacing) Spacing in a function signature. eslint: [`space-before-function-paren`](https://eslint.org/docs/rules/space-before-function-paren) [`space-before-blocks`](https://eslint.org/docs/rules/space-before-blocks) - - - [8.1](#arrows--use-them) When you must use an anonymous function (as when passing an inline callback), use arrow function notation. eslint: [`prefer-arrow-callback`](https://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](https://eslint.org/docs/rules/arrow-spacing.html) + > Why? Consistency is good, and you shouldn’t have to add or remove a space when adding or removing a name. - > Why? It creates a version of the function that executes in the context of `this`, which is usually what you want, and is a more concise syntax. + ```javascript + // bad + const f = function () {}; + const g = function () {}; + const h = function () {}; + + // good + const x = function () {}; + const y = function a() {}; + ``` - > Why not? If you have a fairly complicated function, you might move that logic out into its own named function expression. + - ```javascript - // bad - [1, 2, 3].map(function (x) { - const y = x + 1; - return x * y; - }); +- [7.12](#functions--mutate-params) Never mutate parameters. eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html) - // good - [1, 2, 3].map((x) => { - const y = x + 1; - return x * y; - }); - ``` + > Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller. - - - [8.2](#arrows--implicit-return) If the function body consists of a single statement returning an [expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) without side effects, omit the braces and use the implicit return. Otherwise, keep the braces and use a `return` statement. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](https://eslint.org/docs/rules/arrow-body-style.html) + ```javascript + // bad + function f1(obj) { + obj.key = 1; + } - > Why? Syntactic sugar. It reads well when multiple functions are chained together. + // good + function f2(obj) { + const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; + } + ``` - ```javascript - // bad - [1, 2, 3].map((number) => { - const nextNumber = number + 1; - `A string containing the ${nextNumber}.`; - }); + - // good - [1, 2, 3].map((number) => `A string containing the ${number + 1}.`); +- [7.13](#functions--reassign-params) Never reassign parameters. eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html) - // good - [1, 2, 3].map((number) => { - const nextNumber = number + 1; - return `A string containing the ${nextNumber}.`; - }); + > Why? Reassigning parameters can lead to unexpected behavior, especially when accessing the `arguments` object. It can also cause optimization issues, especially in V8. - // good - [1, 2, 3].map((number, index) => ({ - [index]: number, - })); + ```javascript + // bad + function f1(a) { + a = 1; + // ... + } - // No implicit return with side effects - function foo(callback) { - const val = callback(); - if (val === true) { - // Do something if callback returns true - } + function f2(a) { + if (!a) { + a = 1; } + // ... + } - let bool = false; + // good + function f3(a) { + const b = a || 1; + // ... + } - // bad - foo(() => bool = true); + function f4(a = 1) { + // ... + } + ``` - // good - foo(() => { - bool = true; - }); - ``` - - - - [8.3](#arrows--paren-wrap) In case the expression spans over multiple lines, wrap it in parentheses for better readability. - - > Why? It shows clearly where the function starts and ends. - - ```javascript - // bad - ['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call( - httpMagicObjectWithAVeryLongName, - httpMethod, - ) - ); - - // good - ['get', 'post', 'put'].map((httpMethod) => ( - Object.prototype.hasOwnProperty.call( - httpMagicObjectWithAVeryLongName, - httpMethod, - ) - )); - ``` - - - - [8.4](#arrows--one-arg-parens) Always include parentheses around arguments for clarity and consistency. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens.html) - - > Why? Minimizes diff churn when adding or removing arguments. - - ```javascript - // bad - [1, 2, 3].map(x => x * x); - - // good - [1, 2, 3].map((x) => x * x); - - // bad - [1, 2, 3].map(number => ( - `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!` - )); - - // good - [1, 2, 3].map((number) => ( - `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!` - )); - - // bad - [1, 2, 3].map(x => { - const y = x + 1; - return x * y; - }); + - // good - [1, 2, 3].map((x) => { - const y = x + 1; - return x * y; - }); - ``` +- [7.14](#functions--spread-vs-apply) Prefer the use of the spread operator `...` to call variadic functions. eslint: [`prefer-spread`](https://eslint.org/docs/rules/prefer-spread) - - - [8.5](#arrows--confusing) Avoid confusing arrow function syntax (`=>`) with comparison operators (`<=`, `>=`). eslint: [`no-confusing-arrow`](https://eslint.org/docs/rules/no-confusing-arrow) + > Why? It’s cleaner, you don’t need to supply a context, and you can not easily compose `new` with `apply`. - ```javascript - // bad - const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize; + ```javascript + // bad + const x = [1, 2, 3, 4, 5]; + console.log.apply(console, x); - // bad - const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize; + // good + const x = [1, 2, 3, 4, 5]; + console.log(...x); - // good - const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize); + // bad + new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]))(); - // good - const itemHeight = (item) => { - const { height, largeSize, smallSize } = item; - return height <= 256 ? largeSize : smallSize; - }; - ``` + // good + new Date(...[2016, 8, 5]); + ``` - - - [8.6](#whitespace--implicit-arrow-linebreak) Enforce the location of arrow function bodies with implicit returns. eslint: [`implicit-arrow-linebreak`](https://eslint.org/docs/rules/implicit-arrow-linebreak) + - ```javascript - // bad - (foo) => - bar; +- [7.15](#functions--signature-invocation-indentation) Functions with multiline signatures, or invocations, should be indented just like every other multiline list in this guide: with each item on a line by itself, with a trailing comma on the last item. eslint: [`function-paren-newline`](https://eslint.org/docs/rules/function-paren-newline) - (foo) => - (bar); + ```javascript + // bad + function foo(bar, baz, quux) { + // ... + } - // good - (foo) => bar; - (foo) => (bar); - (foo) => ( - bar - ) - ``` + // good + function foo(bar, baz, quux) { + // ... + } -**[⬆ back to top](#table-of-contents)** + // bad + console.log(foo, bar, baz); -## Classes & Constructors + // good + console.log(foo, bar, baz); + ``` - - - [9.1](#constructors--use-class) Always use `class`. Avoid manipulating `prototype` directly. +**[⬆ back to top](#table-of-contents)** + +## Arrow Functions + + + +- [8.1](#arrows--use-them) When you must use an anonymous function (as when passing an inline callback), use arrow function notation. eslint: [`prefer-arrow-callback`](https://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](https://eslint.org/docs/rules/arrow-spacing.html) + + > Why? It creates a version of the function that executes in the context of `this`, which is usually what you want, and is a more concise syntax. + + > Why not? If you have a fairly complicated function, you might move that logic out into its own named function expression. + + ```javascript + // bad + [1, 2, 3].map(function (x) { + const y = x + 1; + return x * y; + }); + + // good + [1, 2, 3].map((x) => { + const y = x + 1; + return x * y; + }); + ``` + + + +- [8.2](#arrows--implicit-return) If the function body consists of a single statement returning an [expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) without side effects, omit the braces and use the implicit return. Otherwise, keep the braces and use a `return` statement. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](https://eslint.org/docs/rules/arrow-body-style.html) + + > Why? Syntactic sugar. It reads well when multiple functions are chained together. + + ```javascript + // bad + [1, 2, 3].map((number) => { + const nextNumber = number + 1; + `A string containing the ${nextNumber}.`; + }); + + // good + [1, 2, 3].map((number) => `A string containing the ${number + 1}.`); + + // good + [1, 2, 3].map((number) => { + const nextNumber = number + 1; + return `A string containing the ${nextNumber}.`; + }); + + // good + [1, 2, 3].map((number, index) => ({ + [index]: number, + })); + + // No implicit return with side effects + function foo(callback) { + const val = callback(); + if (val === true) { + // Do something if callback returns true + } + } + + let bool = false; + + // bad + foo(() => (bool = true)); + + // good + foo(() => { + bool = true; + }); + ``` + + + +- [8.3](#arrows--paren-wrap) In case the expression spans over multiple lines, wrap it in parentheses for better readability. + + > Why? It shows clearly where the function starts and ends. + + ```javascript + // bad + ['get', 'post', 'put'].map((httpMethod) => + Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName, httpMethod), + ); + + // good + ['get', 'post', 'put'].map((httpMethod) => + Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName, httpMethod), + ); + ``` + + + +- [8.4](#arrows--one-arg-parens) Always include parentheses around arguments for clarity and consistency. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens.html) + + > Why? Minimizes diff churn when adding or removing arguments. + + ```javascript + // bad + [1, 2, 3].map((x) => x * x); + + // good + [1, 2, 3].map((x) => x * x); + + // bad + [1, 2, 3].map( + (number) => + `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`, + ); + + // good + [1, 2, 3].map( + (number) => + `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`, + ); + + // bad + [1, 2, 3].map((x) => { + const y = x + 1; + return x * y; + }); + + // good + [1, 2, 3].map((x) => { + const y = x + 1; + return x * y; + }); + ``` + + + +- [8.5](#arrows--confusing) Avoid confusing arrow function syntax (`=>`) with comparison operators (`<=`, `>=`). eslint: [`no-confusing-arrow`](https://eslint.org/docs/rules/no-confusing-arrow) + + ```javascript + // bad + const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize); + + // bad + const itemHeight = (item) => (item.height >= 256 ? item.largeSize : item.smallSize); + + // good + const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize); + + // good + const itemHeight = (item) => { + const { height, largeSize, smallSize } = item; + return height <= 256 ? largeSize : smallSize; + }; + ``` + + + +- [8.6](#whitespace--implicit-arrow-linebreak) Enforce the location of arrow function bodies with implicit returns. eslint: [`implicit-arrow-linebreak`](https://eslint.org/docs/rules/implicit-arrow-linebreak) + + ```javascript + // bad + (foo) => bar; + + (foo) => bar; + + // good + (foo) => bar; + (foo) => bar; + (foo) => bar; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Classes & Constructors - > Why? `class` syntax is more concise and easier to reason about. + - ```javascript - // bad - function Queue(contents = []) { +- [9.1](#constructors--use-class) Always use `class`. Avoid manipulating `prototype` directly. + + > Why? `class` syntax is more concise and easier to reason about. + + ```javascript + // bad + function Queue(contents = []) { + this.queue = [...contents]; + } + Queue.prototype.pop = function () { + const value = this.queue[0]; + this.queue.splice(0, 1); + return value; + }; + + // good + class Queue { + constructor(contents = []) { this.queue = [...contents]; } - Queue.prototype.pop = function () { + pop() { const value = this.queue[0]; this.queue.splice(0, 1); return value; - }; - - // good - class Queue { - constructor(contents = []) { - this.queue = [...contents]; - } - pop() { - const value = this.queue[0]; - this.queue.splice(0, 1); - return value; - } } - ``` + } + ``` - - - [9.2](#constructors--extends) Use `extends` for inheritance. + - > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`. +- [9.2](#constructors--extends) Use `extends` for inheritance. - ```javascript - // bad - const inherits = require('inherits'); - function PeekableQueue(contents) { - Queue.apply(this, contents); - } - inherits(PeekableQueue, Queue); - PeekableQueue.prototype.peek = function () { - return this.queue[0]; - }; + > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`. - // good - class PeekableQueue extends Queue { - peek() { - return this.queue[0]; - } + ```javascript + // bad + const inherits = require('inherits'); + function PeekableQueue(contents) { + Queue.apply(this, contents); + } + inherits(PeekableQueue, Queue); + PeekableQueue.prototype.peek = function () { + return this.queue[0]; + }; + + // good + class PeekableQueue extends Queue { + peek() { + return this.queue[0]; } - ``` + } + ``` - - - [9.3](#constructors--chaining) Methods can return `this` to help with method chaining. + - ```javascript - // bad - Jedi.prototype.jump = function () { - this.jumping = true; - return true; - }; +- [9.3](#constructors--chaining) Methods can return `this` to help with method chaining. - Jedi.prototype.setHeight = function (height) { - this.height = height; - }; + ```javascript + // bad + Jedi.prototype.jump = function () { + this.jumping = true; + return true; + }; - const luke = new Jedi(); - luke.jump(); // => true - luke.setHeight(20); // => undefined + Jedi.prototype.setHeight = function (height) { + this.height = height; + }; - // good - class Jedi { - jump() { - this.jumping = true; - return this; - } + const luke = new Jedi(); + luke.jump(); // => true + luke.setHeight(20); // => undefined - setHeight(height) { - this.height = height; - return this; - } + // good + class Jedi { + jump() { + this.jumping = true; + return this; } - const luke = new Jedi(); + setHeight(height) { + this.height = height; + return this; + } + } - luke.jump() - .setHeight(20); - ``` + const luke = new Jedi(); - - - [9.4](#constructors--tostring) It’s okay to write a custom `toString()` method, just make sure it works successfully and causes no side effects. + luke.jump().setHeight(20); + ``` - ```javascript - class Jedi { - constructor(options = {}) { - this.name = options.name || 'no name'; - } + - getName() { - return this.name; - } +- [9.4](#constructors--tostring) It’s okay to write a custom `toString()` method, just make sure it works successfully and causes no side effects. - toString() { - return `Jedi - ${this.getName()}`; - } + ```javascript + class Jedi { + constructor(options = {}) { + this.name = options.name || 'no name'; + } + + getName() { + return this.name; + } + + toString() { + return `Jedi - ${this.getName()}`; } - ``` + } + ``` - - - [9.5](#constructors--no-useless) Classes have a default constructor if one is not specified. An empty constructor function or one that just delegates to a parent class is unnecessary. eslint: [`no-useless-constructor`](https://eslint.org/docs/rules/no-useless-constructor) + - ```javascript - // bad - class Jedi { - constructor() {} +- [9.5](#constructors--no-useless) Classes have a default constructor if one is not specified. An empty constructor function or one that just delegates to a parent class is unnecessary. eslint: [`no-useless-constructor`](https://eslint.org/docs/rules/no-useless-constructor) - getName() { - return this.name; - } + ```javascript + // bad + class Jedi { + constructor() {} + + getName() { + return this.name; } + } - // bad - class Rey extends Jedi { - constructor(...args) { - super(...args); - } + // bad + class Rey extends Jedi { + constructor(...args) { + super(...args); } + } - // good - class Rey extends Jedi { - constructor(...args) { - super(...args); - this.name = 'Rey'; - } + // good + class Rey extends Jedi { + constructor(...args) { + super(...args); + this.name = 'Rey'; } - ``` + } + ``` + + - - - [9.6](#classes--no-duplicate-members) Avoid duplicate class members. eslint: [`no-dupe-class-members`](https://eslint.org/docs/rules/no-dupe-class-members) +- [9.6](#classes--no-duplicate-members) Avoid duplicate class members. eslint: [`no-dupe-class-members`](https://eslint.org/docs/rules/no-dupe-class-members) - > Why? Duplicate class member declarations will silently prefer the last one - having duplicates is almost certainly a bug. + > Why? Duplicate class member declarations will silently prefer the last one - having duplicates is almost certainly a bug. - ```javascript - // bad - class Foo { - bar() { return 1; } - bar() { return 2; } + ```javascript + // bad + class Foo { + bar() { + return 1; + } + bar() { + return 2; } + } - // good - class Foo { - bar() { return 1; } + // good + class Foo { + bar() { + return 1; } + } - // good - class Foo { - bar() { return 2; } + // good + class Foo { + bar() { + return 2; } - ``` + } + ``` - - - [9.7](#classes--methods-use-this) Class methods should use `this` or be made into a static method unless an external library or framework requires to use specific non-static methods. Being an instance method should indicate that it behaves differently based on properties of the receiver. eslint: [`class-methods-use-this`](https://eslint.org/docs/rules/class-methods-use-this) + - ```javascript - // bad - class Foo { - bar() { - console.log('bar'); - } +- [9.7](#classes--methods-use-this) Class methods should use `this` or be made into a static method unless an external library or framework requires to use specific non-static methods. Being an instance method should indicate that it behaves differently based on properties of the receiver. eslint: [`class-methods-use-this`](https://eslint.org/docs/rules/class-methods-use-this) + + ```javascript + // bad + class Foo { + bar() { + console.log('bar'); } + } - // good - this is used - class Foo { - bar() { - console.log(this.bar); - } + // good - this is used + class Foo { + bar() { + console.log(this.bar); } + } - // good - constructor is exempt - class Foo { - constructor() { - // ... - } + // good - constructor is exempt + class Foo { + constructor() { + // ... } + } - // good - static methods aren't expected to use this - class Foo { - static bar() { - console.log('bar'); - } + // good - static methods aren't expected to use this + class Foo { + static bar() { + console.log('bar'); } - ``` + } + ``` **[⬆ back to top](#table-of-contents)** ## Modules - - - [10.1](#modules--use-them) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system. - - > Why? Modules are the future, let’s start using the future now. - - ```javascript - // bad - const AirbnbStyleGuide = require('./AirbnbStyleGuide'); - module.exports = AirbnbStyleGuide.es6; + + +- [10.1](#modules--use-them) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system. + + > Why? Modules are the future, let’s start using the future now. + + ```javascript + // bad + const AirbnbStyleGuide = require('./AirbnbStyleGuide'); + module.exports = AirbnbStyleGuide.es6; + + // ok + import AirbnbStyleGuide from './AirbnbStyleGuide'; + export default AirbnbStyleGuide.es6; + + // best + import { es6 } from './AirbnbStyleGuide'; + export default es6; + ``` + + + +- [10.2](#modules--no-wildcard) Do not use wildcard imports. + + > Why? This makes sure you have a single default export. + + ```javascript + // bad + import * as AirbnbStyleGuide from './AirbnbStyleGuide'; + + // good + import AirbnbStyleGuide from './AirbnbStyleGuide'; + ``` + + + +- [10.3](#modules--no-export-from-import) And do not export directly from an import. + + > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. + + ```javascript + // bad + // filename es6.js + export { es6 as default } from './AirbnbStyleGuide'; + + // good + // filename es6.js + import { es6 } from './AirbnbStyleGuide'; + export default es6; + ``` + + + +- [10.4](#modules--no-duplicate-imports) Only import from a path in one place. + eslint: [`no-duplicate-imports`](https://eslint.org/docs/rules/no-duplicate-imports) + + > Why? Having multiple lines that import from the same path can make code harder to maintain. + + ```javascript + // bad + import foo from 'foo'; + // … some other imports … // + import { named1, named2 } from 'foo'; + + // good + import foo, { named1, named2 } from 'foo'; + + // good + import foo, { named1, named2 } from 'foo'; + ``` + + + +- [10.5](#modules--no-mutable-exports) Do not export mutable bindings. + eslint: [`import/no-mutable-exports`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md) + + > Why? Mutation should be avoided in general, but in particular when exporting mutable bindings. While this technique may be needed for some special cases, in general, only constant references should be exported. + + ```javascript + // bad + let foo = 3; + export { foo }; + + // good + const foo = 3; + export { foo }; + ``` + + + +- [10.6](#modules--prefer-default-export) In modules with a single export, prefer default export over named export. + eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md) + + > Why? To encourage more files that only ever export one thing, which is better for readability and maintainability. + + ```javascript + // bad + export function foo() {} + + // good + export default function foo() {} + ``` + + + +- [10.7](#modules--imports-first) Put all `import`s above non-import statements. + eslint: [`import/first`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/first.md) + + > Why? Since `import`s are hoisted, keeping them all at the top prevents surprising behavior. + + ```javascript + // bad + import foo from 'foo'; + foo.init(); + + import bar from 'bar'; + + // good + import foo from 'foo'; + import bar from 'bar'; + + foo.init(); + ``` + + + +- [10.8](#modules--multiline-imports-over-newlines) Multiline imports should be indented just like multiline array and object literals. + eslint: [`object-curly-newline`](https://eslint.org/docs/rules/object-curly-newline) + + > Why? The curly braces follow the same indentation rules as every other curly brace block in the style guide, as do the trailing commas. + + ```javascript + // bad + import { longNameA, longNameB, longNameC, longNameD, longNameE } from 'path'; + + // good + import { longNameA, longNameB, longNameC, longNameD, longNameE } from 'path'; + ``` + + - // ok - import AirbnbStyleGuide from './AirbnbStyleGuide'; - export default AirbnbStyleGuide.es6; +- [10.9](#modules--no-webpack-loader-syntax) Disallow Webpack loader syntax in module import statements. + eslint: [`import/no-webpack-loader-syntax`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md) - // best - import { es6 } from './AirbnbStyleGuide'; - export default es6; - ``` - - - - [10.2](#modules--no-wildcard) Do not use wildcard imports. + > Why? Since using Webpack syntax in the imports couples the code to a module bundler. Prefer using the loader syntax in `webpack.config.js`. - > Why? This makes sure you have a single default export. + ```javascript + // bad + import fooSass from 'css!sass!foo.scss'; + import barCss from 'style!css!bar.css'; + + // good + import fooSass from 'foo.scss'; + import barCss from 'bar.css'; + ``` + + - ```javascript - // bad - import * as AirbnbStyleGuide from './AirbnbStyleGuide'; +- [10.10](#modules--import-extensions) Do not include JavaScript filename extensions + eslint: [`import/extensions`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md) - // good - import AirbnbStyleGuide from './AirbnbStyleGuide'; - ``` - - - - [10.3](#modules--no-export-from-import) And do not export directly from an import. - - > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. - - ```javascript - // bad - // filename es6.js - export { es6 as default } from './AirbnbStyleGuide'; - - // good - // filename es6.js - import { es6 } from './AirbnbStyleGuide'; - export default es6; - ``` - - - - [10.4](#modules--no-duplicate-imports) Only import from a path in one place. - eslint: [`no-duplicate-imports`](https://eslint.org/docs/rules/no-duplicate-imports) - > Why? Having multiple lines that import from the same path can make code harder to maintain. - - ```javascript - // bad - import foo from 'foo'; - // … some other imports … // - import { named1, named2 } from 'foo'; - - // good - import foo, { named1, named2 } from 'foo'; - - // good - import foo, { - named1, - named2, - } from 'foo'; - ``` - - - - [10.5](#modules--no-mutable-exports) Do not export mutable bindings. - eslint: [`import/no-mutable-exports`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md) - > Why? Mutation should be avoided in general, but in particular when exporting mutable bindings. While this technique may be needed for some special cases, in general, only constant references should be exported. - - ```javascript - // bad - let foo = 3; - export { foo }; - - // good - const foo = 3; - export { foo }; - ``` - - - - [10.6](#modules--prefer-default-export) In modules with a single export, prefer default export over named export. - eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md) - > Why? To encourage more files that only ever export one thing, which is better for readability and maintainability. - - ```javascript - // bad - export function foo() {} - - // good - export default function foo() {} - ``` - - - - [10.7](#modules--imports-first) Put all `import`s above non-import statements. - eslint: [`import/first`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/first.md) - > Why? Since `import`s are hoisted, keeping them all at the top prevents surprising behavior. - - ```javascript - // bad - import foo from 'foo'; - foo.init(); - - import bar from 'bar'; - - // good - import foo from 'foo'; - import bar from 'bar'; - - foo.init(); - ``` - - - - [10.8](#modules--multiline-imports-over-newlines) Multiline imports should be indented just like multiline array and object literals. - eslint: [`object-curly-newline`](https://eslint.org/docs/rules/object-curly-newline) - - > Why? The curly braces follow the same indentation rules as every other curly brace block in the style guide, as do the trailing commas. - - ```javascript - // bad - import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path'; - - // good - import { - longNameA, - longNameB, - longNameC, - longNameD, - longNameE, - } from 'path'; - ``` - - - - [10.9](#modules--no-webpack-loader-syntax) Disallow Webpack loader syntax in module import statements. - eslint: [`import/no-webpack-loader-syntax`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md) - > Why? Since using Webpack syntax in the imports couples the code to a module bundler. Prefer using the loader syntax in `webpack.config.js`. - - ```javascript - // bad - import fooSass from 'css!sass!foo.scss'; - import barCss from 'style!css!bar.css'; - - // good - import fooSass from 'foo.scss'; - import barCss from 'bar.css'; - ``` - - - - [10.10](#modules--import-extensions) Do not include JavaScript filename extensions - eslint: [`import/extensions`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md) - > Why? Including extensions inhibits refactoring, and inappropriately hardcodes implementation details of the module you're importing in every consumer. - - ```javascript - // bad - import foo from './foo.js'; - import bar from './bar.jsx'; - import baz from './baz/index.jsx'; - - // good - import foo from './foo'; - import bar from './bar'; - import baz from './baz'; - ``` + > Why? Including extensions inhibits refactoring, and inappropriately hardcodes implementation details of the module you're importing in every consumer. + + ```javascript + // bad + import foo from './foo.js'; + import bar from './bar.jsx'; + import baz from './baz/index.jsx'; + + // good + import foo from './foo'; + import bar from './bar'; + import baz from './baz'; + ``` **[⬆ back to top](#table-of-contents)** ## Iterators and Generators - - - [11.1](#iterators--nope) Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like `for-in` or `for-of`. eslint: [`no-iterator`](https://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](https://eslint.org/docs/rules/no-restricted-syntax) + - > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects. +- [11.1](#iterators--nope) Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like `for-in` or `for-of`. eslint: [`no-iterator`](https://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](https://eslint.org/docs/rules/no-restricted-syntax) - > Use `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... to iterate over arrays, and `Object.keys()` / `Object.values()` / `Object.entries()` to produce arrays so you can iterate over objects. + > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects. - ```javascript - const numbers = [1, 2, 3, 4, 5]; + > Use `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... to iterate over arrays, and `Object.keys()` / `Object.values()` / `Object.entries()` to produce arrays so you can iterate over objects. - // bad - let sum = 0; - for (let num of numbers) { - sum += num; - } - sum === 15; + ```javascript + const numbers = [1, 2, 3, 4, 5]; - // good - let sum = 0; - numbers.forEach((num) => { - sum += num; - }); - sum === 15; + // bad + let sum = 0; + for (let num of numbers) { + sum += num; + } + sum === 15; + + // good + let sum = 0; + numbers.forEach((num) => { + sum += num; + }); + sum === 15; + + // best (use the functional force) + const sum = numbers.reduce((total, num) => total + num, 0); + sum === 15; + + // bad + const increasedByOne = []; + for (let i = 0; i < numbers.length; i++) { + increasedByOne.push(numbers[i] + 1); + } - // best (use the functional force) - const sum = numbers.reduce((total, num) => total + num, 0); - sum === 15; + // good + const increasedByOne = []; + numbers.forEach((num) => { + increasedByOne.push(num + 1); + }); - // bad - const increasedByOne = []; - for (let i = 0; i < numbers.length; i++) { - increasedByOne.push(numbers[i] + 1); - } + // best (keeping it functional) + const increasedByOne = numbers.map((num) => num + 1); + ``` - // good - const increasedByOne = []; - numbers.forEach((num) => { - increasedByOne.push(num + 1); - }); + - // best (keeping it functional) - const increasedByOne = numbers.map((num) => num + 1); - ``` +- [11.2](#generators--nope) Don’t use generators for now. - - - [11.2](#generators--nope) Don’t use generators for now. + > Why? They don’t transpile well to ES5. - > Why? They don’t transpile well to ES5. + - - - [11.3](#generators--spacing) If you must use generators, or if you disregard [our advice](#generators--nope), make sure their function signature is spaced properly. eslint: [`generator-star-spacing`](https://eslint.org/docs/rules/generator-star-spacing) +- [11.3](#generators--spacing) If you must use generators, or if you disregard [our advice](#generators--nope), make sure their function signature is spaced properly. eslint: [`generator-star-spacing`](https://eslint.org/docs/rules/generator-star-spacing) - > Why? `function` and `*` are part of the same conceptual keyword - `*` is not a modifier for `function`, `function*` is a unique construct, different from `function`. + > Why? `function` and `*` are part of the same conceptual keyword - `*` is not a modifier for `function`, `function*` is a unique construct, different from `function`. - ```javascript - // bad - function * foo() { - // ... - } + ```javascript + // bad + function* foo() { + // ... + } - // bad - const bar = function * () { - // ... - }; + // bad + const bar = function* () { + // ... + }; - // bad - const baz = function *() { - // ... - }; + // bad + const baz = function* () { + // ... + }; - // bad - const quux = function*() { - // ... - }; + // bad + const quux = function* () { + // ... + }; - // bad - function*foo() { - // ... + // bad + function* foo() { + // ... + } + + // bad + function* foo() { + // ... + } + + // very bad + function* foo() { + // ... + } + + // very bad + const wat = function* () { + // ... + }; + + // good + function* foo() { + // ... + } + + // good + const foo = function* () { + // ... + }; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Properties + + + +- [12.1](#properties--dot) Use dot notation when accessing properties. eslint: [`dot-notation`](https://eslint.org/docs/rules/dot-notation.html) + + ```javascript + const luke = { + jedi: true, + age: 28, + }; + + // bad + const isJedi = luke['jedi']; + + // good + const isJedi = luke.jedi; + ``` + + + +- [12.2](#properties--bracket) Use bracket notation `[]` when accessing properties with a variable. + + ```javascript + const luke = { + jedi: true, + age: 28, + }; + + function getProp(prop) { + return luke[prop]; + } + + const isJedi = getProp('jedi'); + ``` + + + +- [12.3](#es2016-properties--exponentiation-operator) Use exponentiation operator `**` when calculating exponentiations. eslint: [`no-restricted-properties`](https://eslint.org/docs/rules/no-restricted-properties). + + ```javascript + // bad + const binary = Math.pow(2, 10); + + // good + const binary = 2 ** 10; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Variables + + + +- [13.1](#variables--const) Always use `const` or `let` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. eslint: [`no-undef`](https://eslint.org/docs/rules/no-undef) [`prefer-const`](https://eslint.org/docs/rules/prefer-const) + + ```javascript + // bad + superPower = new SuperPower(); + + // good + const superPower = new SuperPower(); + ``` + + + +- [13.2](#variables--one-const) Use one `const` or `let` declaration per variable or assignment. eslint: [`one-var`](https://eslint.org/docs/rules/one-var.html) + + > Why? It’s easier to add new variable declarations this way, and you never have to worry about swapping out a `;` for a `,` or introducing punctuation-only diffs. You can also step through each declaration with the debugger, instead of jumping through all of them at once. + + ```javascript + // bad + const items = getItems(), + goSportsTeam = true, + dragonball = 'z'; + + // bad + // (compare to above, and try to spot the mistake) + const items = getItems(), + goSportsTeam = true; + dragonball = 'z'; + + // good + const items = getItems(); + const goSportsTeam = true; + const dragonball = 'z'; + ``` + + + +- [13.3](#variables--const-let-group) Group all your `const`s and then group all your `let`s. + + > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. + + ```javascript + // bad + let i, + len, + dragonball, + items = getItems(), + goSportsTeam = true; + + // bad + let i; + const items = getItems(); + let dragonball; + const goSportsTeam = true; + let len; + + // good + const goSportsTeam = true; + const items = getItems(); + let dragonball; + let i; + let length; + ``` + + + +- [13.4](#variables--define-where-used) Assign variables where you need them, but place them in a reasonable place. + + > Why? `let` and `const` are block scoped and not function scoped. + + ```javascript + // bad - unnecessary function call + function checkName(hasName) { + const name = getName(); + + if (hasName === 'test') { + return false; } - // bad - function *foo() { - // ... + if (name === 'test') { + this.setName(''); + return false; } - // very bad - function - * - foo() { - // ... + return name; + } + + // good + function checkName(hasName) { + if (hasName === 'test') { + return false; } - // very bad - const wat = function - * - () { - // ... - }; + const name = getName(); - // good - function* foo() { - // ... + if (name === 'test') { + this.setName(''); + return false; } - // good - const foo = function* () { - // ... - }; - ``` + return name; + } + ``` + + + +- [13.5](#variables--no-chain-assignment) Don’t chain variable assignments. eslint: [`no-multi-assign`](https://eslint.org/docs/rules/no-multi-assign) + + > Why? Chaining variable assignments creates implicit global variables. + + ```javascript + // bad + (function example() { + // JavaScript interprets this as + // let a = ( b = ( c = 1 ) ); + // The let keyword only applies to variable a; variables b and c become + // global variables. + let a = (b = c = 1); + })(); + + console.log(a); // throws ReferenceError + console.log(b); // 1 + console.log(c); // 1 + + // good + (function example() { + let a = 1; + let b = a; + let c = a; + })(); + + console.log(a); // throws ReferenceError + console.log(b); // throws ReferenceError + console.log(c); // throws ReferenceError + + // the same applies for `const` + ``` + + + +- [13.6](#variables--unary-increment-decrement) Avoid using unary increments and decrements (`++`, `--`). eslint [`no-plusplus`](https://eslint.org/docs/rules/no-plusplus) + + > Why? Per the eslint documentation, unary increment and decrement statements are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application. It is also more expressive to mutate your values with statements like `num += 1` instead of `num++` or `num ++`. Disallowing unary increment and decrement statements also prevents you from pre-incrementing/pre-decrementing values unintentionally which can also cause unexpected behavior in your programs. + + ```javascript + // bad + + const array = [1, 2, 3]; + let num = 1; + num++; + --num; + + let sum = 0; + let truthyCount = 0; + for (let i = 0; i < array.length; i++) { + let value = array[i]; + sum += value; + if (value) { + truthyCount++; + } + } + + // good + + const array = [1, 2, 3]; + let num = 1; + num += 1; + num -= 1; + + const sum = array.reduce((a, b) => a + b, 0); + const truthyCount = array.filter(Boolean).length; + ``` + + + +- [13.7](#variables--linebreak) Avoid linebreaks before or after `=` in an assignment. If your assignment violates [`max-len`](https://eslint.org/docs/rules/max-len.html), surround the value in parens. eslint [`operator-linebreak`](https://eslint.org/docs/rules/operator-linebreak.html). + + > Why? Linebreaks surrounding `=` can obfuscate the value of an assignment. + + ```javascript + // bad + const foo = superLongLongLongLongLongLongLongLongFunctionName(); + + // bad + const foo = 'superLongLongLongLongLongLongLongLongString'; + + // good + const foo = superLongLongLongLongLongLongLongLongFunctionName(); + + // good + const foo = 'superLongLongLongLongLongLongLongLongString'; + ``` + + + +- [13.8](#variables--no-unused-vars) Disallow unused variables. eslint: [`no-unused-vars`](https://eslint.org/docs/rules/no-unused-vars) + + > Why? Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers. + + ```javascript + // bad + + var some_unused_var = 42; + + // Write-only variables are not considered as used. + var y = 10; + y = 5; + + // A read for a modification of itself is not considered as used. + var z = 0; + z = z + 1; + + // Unused function arguments. + function getX(x, y) { + return x; + } + + // good + + function getXPlusY(x, y) { + return x + y; + } + + var x = 1; + var y = a + 2; + + alert(getXPlusY(x, y)); + + // 'type' is ignored even if unused because it has a rest property sibling. + // This is a form of extracting an object that omits the specified keys. + var { type, ...coords } = data; + // 'coords' is now the 'data' object without its 'type' property. + ``` **[⬆ back to top](#table-of-contents)** -## Properties +## Hoisting + + + +- [14.1](#hoisting--about) `var` declarations get hoisted to the top of their closest enclosing function scope, their assignment does not. `const` and `let` declarations are blessed with a new concept called [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone). It’s important to know why [typeof is no longer safe](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15). + + ```javascript + // we know this wouldn’t work (assuming there + // is no notDefined global variable) + function example() { + console.log(notDefined); // => throws a ReferenceError + } + + // creating a variable declaration after you + // reference the variable will work due to + // variable hoisting. Note: the assignment + // value of `true` is not hoisted. + function example() { + console.log(declaredButNotAssigned); // => undefined + var declaredButNotAssigned = true; + } + + // the interpreter is hoisting the variable + // declaration to the top of the scope, + // which means our example could be rewritten as: + function example() { + let declaredButNotAssigned; + console.log(declaredButNotAssigned); // => undefined + declaredButNotAssigned = true; + } + + // using const and let + function example() { + console.log(declaredButNotAssigned); // => throws a ReferenceError + console.log(typeof declaredButNotAssigned); // => throws a ReferenceError + const declaredButNotAssigned = true; + } + ``` + + - - - [12.1](#properties--dot) Use dot notation when accessing properties. eslint: [`dot-notation`](https://eslint.org/docs/rules/dot-notation.html) +- [14.2](#hoisting--anon-expressions) Anonymous function expressions hoist their variable name, but not the function assignment. - ```javascript - const luke = { - jedi: true, - age: 28, + ```javascript + function example() { + console.log(anonymous); // => undefined + + anonymous(); // => TypeError anonymous is not a function + + var anonymous = function () { + console.log('anonymous function expression'); }; + } + ``` - // bad - const isJedi = luke['jedi']; + - // good - const isJedi = luke.jedi; - ``` +- [14.3](#hoisting--named-expressions) Named function expressions hoist the variable name, not the function name or the function body. - - - [12.2](#properties--bracket) Use bracket notation `[]` when accessing properties with a variable. + ```javascript + function example() { + console.log(named); // => undefined - ```javascript - const luke = { - jedi: true, - age: 28, + named(); // => TypeError named is not a function + + superPower(); // => ReferenceError superPower is not defined + + var named = function superPower() { + console.log('Flying'); }; + } - function getProp(prop) { - return luke[prop]; - } + // the same is true when the function name + // is the same as the variable name. + function example() { + console.log(named); // => undefined - const isJedi = getProp('jedi'); - ``` + named(); // => TypeError named is not a function - - - [12.3](#es2016-properties--exponentiation-operator) Use exponentiation operator `**` when calculating exponentiations. eslint: [`no-restricted-properties`](https://eslint.org/docs/rules/no-restricted-properties). + var named = function named() { + console.log('named'); + }; + } + ``` - ```javascript - // bad - const binary = Math.pow(2, 10); + + +- [14.4](#hoisting--declarations) Function declarations hoist their name and the function body. + + ```javascript + function example() { + superPower(); // => Flying + + function superPower() { + console.log('Flying'); + } + } + ``` - // good - const binary = 2 ** 10; - ``` +- For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) by [Ben Cherry](http://www.adequatelygood.com/). **[⬆ back to top](#table-of-contents)** -## Variables +## Comparison Operators & Equality - - - [13.1](#variables--const) Always use `const` or `let` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. eslint: [`no-undef`](https://eslint.org/docs/rules/no-undef) [`prefer-const`](https://eslint.org/docs/rules/prefer-const) - - ```javascript - // bad - superPower = new SuperPower(); - - // good - const superPower = new SuperPower(); - ``` - - - - [13.2](#variables--one-const) Use one `const` or `let` declaration per variable or assignment. eslint: [`one-var`](https://eslint.org/docs/rules/one-var.html) - - > Why? It’s easier to add new variable declarations this way, and you never have to worry about swapping out a `;` for a `,` or introducing punctuation-only diffs. You can also step through each declaration with the debugger, instead of jumping through all of them at once. - - ```javascript - // bad - const items = getItems(), - goSportsTeam = true, - dragonball = 'z'; - - // bad - // (compare to above, and try to spot the mistake) - const items = getItems(), - goSportsTeam = true; - dragonball = 'z'; - - // good - const items = getItems(); - const goSportsTeam = true; - const dragonball = 'z'; - ``` - - - - [13.3](#variables--const-let-group) Group all your `const`s and then group all your `let`s. - - > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. - - ```javascript - // bad - let i, len, dragonball, - items = getItems(), - goSportsTeam = true; - - // bad - let i; - const items = getItems(); - let dragonball; - const goSportsTeam = true; - let len; - - // good - const goSportsTeam = true; - const items = getItems(); - let dragonball; - let i; - let length; - ``` - - - - [13.4](#variables--define-where-used) Assign variables where you need them, but place them in a reasonable place. - - > Why? `let` and `const` are block scoped and not function scoped. - - ```javascript - // bad - unnecessary function call - function checkName(hasName) { - const name = getName(); - - if (hasName === 'test') { - return false; - } + - if (name === 'test') { - this.setName(''); - return false; - } +- [15.1](#comparison--eqeqeq) Use `===` and `!==` over `==` and `!=`. eslint: [`eqeqeq`](https://eslint.org/docs/rules/eqeqeq.html) - return name; - } + - // good - function checkName(hasName) { - if (hasName === 'test') { - return false; - } +- [15.2](#comparison--if) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: + + - **Objects** evaluate to **true** + - **Undefined** evaluates to **false** + - **Null** evaluates to **false** + - **Booleans** evaluate to **the value of the boolean** + - **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** + - **Strings** evaluate to **false** if an empty string `''`, otherwise **true** + + ```javascript + if ([0] && []) { + // true + // an array (even an empty one) is an object, objects will evaluate to true + } + ``` + + + +- [15.3](#comparison--shortcuts) Use shortcuts for booleans, but explicit comparisons for strings and numbers. + + ```javascript + // bad + if (isValid === true) { + // ... + } + + // good + if (isValid) { + // ... + } + + // bad + if (name) { + // ... + } + + // good + if (name !== '') { + // ... + } + + // bad + if (collection.length) { + // ... + } + + // good + if (collection.length > 0) { + // ... + } + ``` + + + +- [15.4](#comparison--moreinfo) For more information see [Truth Equality and JavaScript](https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. + + + +- [15.5](#comparison--switch-blocks) Use braces to create blocks in `case` and `default` clauses that contain lexical declarations (e.g. `let`, `const`, `function`, and `class`). eslint: [`no-case-declarations`](https://eslint.org/docs/rules/no-case-declarations.html) - const name = getName(); + > Why? Lexical declarations are visible in the entire `switch` block but only get initialized when assigned, which only happens when its `case` is reached. This causes problems when multiple `case` clauses attempt to define the same thing. - if (name === 'test') { - this.setName(''); - return false; + ```javascript + // bad + switch (foo) { + case 1: + let x = 1; + break; + case 2: + const y = 2; + break; + case 3: + function f() { + // ... } + break; + default: + class C {} + } - return name; + // good + switch (foo) { + case 1: { + let x = 1; + break; + } + case 2: { + const y = 2; + break; } - ``` - - - - [13.5](#variables--no-chain-assignment) Don’t chain variable assignments. eslint: [`no-multi-assign`](https://eslint.org/docs/rules/no-multi-assign) - - > Why? Chaining variable assignments creates implicit global variables. - - ```javascript - // bad - (function example() { - // JavaScript interprets this as - // let a = ( b = ( c = 1 ) ); - // The let keyword only applies to variable a; variables b and c become - // global variables. - let a = b = c = 1; - }()); - - console.log(a); // throws ReferenceError - console.log(b); // 1 - console.log(c); // 1 - - // good - (function example() { - let a = 1; - let b = a; - let c = a; - }()); - - console.log(a); // throws ReferenceError - console.log(b); // throws ReferenceError - console.log(c); // throws ReferenceError - - // the same applies for `const` - ``` - - - - [13.6](#variables--unary-increment-decrement) Avoid using unary increments and decrements (`++`, `--`). eslint [`no-plusplus`](https://eslint.org/docs/rules/no-plusplus) - - > Why? Per the eslint documentation, unary increment and decrement statements are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application. It is also more expressive to mutate your values with statements like `num += 1` instead of `num++` or `num ++`. Disallowing unary increment and decrement statements also prevents you from pre-incrementing/pre-decrementing values unintentionally which can also cause unexpected behavior in your programs. - - ```javascript - // bad - - const array = [1, 2, 3]; - let num = 1; - num++; - --num; - - let sum = 0; - let truthyCount = 0; - for (let i = 0; i < array.length; i++) { - let value = array[i]; - sum += value; - if (value) { - truthyCount++; + case 3: { + function f() { + // ... } + break; } + case 4: + bar(); + break; + default: { + class C {} + } + } + ``` - // good - - const array = [1, 2, 3]; - let num = 1; - num += 1; - num -= 1; + - const sum = array.reduce((a, b) => a + b, 0); - const truthyCount = array.filter(Boolean).length; - ``` +- [15.6](#comparison--nested-ternaries) Ternaries should not be nested and generally be single line expressions. eslint: [`no-nested-ternary`](https://eslint.org/docs/rules/no-nested-ternary.html) - - - [13.7](#variables--linebreak) Avoid linebreaks before or after `=` in an assignment. If your assignment violates [`max-len`](https://eslint.org/docs/rules/max-len.html), surround the value in parens. eslint [`operator-linebreak`](https://eslint.org/docs/rules/operator-linebreak.html). + ```javascript + // bad + const foo = maybe1 > maybe2 ? 'bar' : value1 > value2 ? 'baz' : null; - > Why? Linebreaks surrounding `=` can obfuscate the value of an assignment. + // split into 2 separated ternary expressions + const maybeNull = value1 > value2 ? 'baz' : null; - ```javascript - // bad - const foo = - superLongLongLongLongLongLongLongLongFunctionName(); + // better + const foo = maybe1 > maybe2 ? 'bar' : maybeNull; - // bad - const foo - = 'superLongLongLongLongLongLongLongLongString'; + // best + const foo = maybe1 > maybe2 ? 'bar' : maybeNull; + ``` - // good - const foo = ( - superLongLongLongLongLongLongLongLongFunctionName() - ); + - // good - const foo = 'superLongLongLongLongLongLongLongLongString'; - ``` +- [15.7](#comparison--unneeded-ternary) Avoid unneeded ternary statements. eslint: [`no-unneeded-ternary`](https://eslint.org/docs/rules/no-unneeded-ternary.html) - - - [13.8](#variables--no-unused-vars) Disallow unused variables. eslint: [`no-unused-vars`](https://eslint.org/docs/rules/no-unused-vars) + ```javascript + // bad + const foo = a ? a : b; + const bar = c ? true : false; + const baz = c ? false : true; + + // good + const foo = a || b; + const bar = !!c; + const baz = !c; + ``` - > Why? Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers. + - ```javascript - // bad +- [15.8](#comparison--no-mixed-operators) When mixing operators, enclose them in parentheses. The only exception is the standard arithmetic operators: `+`, `-`, and `**` since their precedence is broadly understood. We recommend enclosing `/` and `*` in parentheses because their precedence can be ambiguous when they are mixed. + eslint: [`no-mixed-operators`](https://eslint.org/docs/rules/no-mixed-operators.html) - var some_unused_var = 42; + > Why? This improves readability and clarifies the developer’s intention. - // Write-only variables are not considered as used. - var y = 10; - y = 5; + ```javascript + // bad + const foo = (a && b < 0) || c > 0 || d + 1 === 0; - // A read for a modification of itself is not considered as used. - var z = 0; - z = z + 1; + // bad + const bar = a ** b - (5 % d); - // Unused function arguments. - function getX(x, y) { - return x; - } + // bad + // one may be confused into thinking (a || b) && c + if (a || (b && c)) { + return d; + } - // good + // bad + const bar = a + (b / c) * d; - function getXPlusY(x, y) { - return x + y; - } + // good + const foo = (a && b < 0) || c > 0 || d + 1 === 0; - var x = 1; - var y = a + 2; + // good + const bar = a ** b - (5 % d); - alert(getXPlusY(x, y)); + // good + if (a || (b && c)) { + return d; + } - // 'type' is ignored even if unused because it has a rest property sibling. - // This is a form of extracting an object that omits the specified keys. - var { type, ...coords } = data; - // 'coords' is now the 'data' object without its 'type' property. - ``` + // good + const bar = a + (b / c) * d; + ``` **[⬆ back to top](#table-of-contents)** -## Hoisting +## Blocks - - - [14.1](#hoisting--about) `var` declarations get hoisted to the top of their closest enclosing function scope, their assignment does not. `const` and `let` declarations are blessed with a new concept called [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone). It’s important to know why [typeof is no longer safe](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15). + - ```javascript - // we know this wouldn’t work (assuming there - // is no notDefined global variable) - function example() { - console.log(notDefined); // => throws a ReferenceError - } +- [16.1](#blocks--braces) Use braces with all multiline blocks. eslint: [`nonblock-statement-body-position`](https://eslint.org/docs/rules/nonblock-statement-body-position) - // creating a variable declaration after you - // reference the variable will work due to - // variable hoisting. Note: the assignment - // value of `true` is not hoisted. - function example() { - console.log(declaredButNotAssigned); // => undefined - var declaredButNotAssigned = true; - } + ```javascript + // bad + if (test) return false; - // the interpreter is hoisting the variable - // declaration to the top of the scope, - // which means our example could be rewritten as: - function example() { - let declaredButNotAssigned; - console.log(declaredButNotAssigned); // => undefined - declaredButNotAssigned = true; - } + // good + if (test) return false; - // using const and let - function example() { - console.log(declaredButNotAssigned); // => throws a ReferenceError - console.log(typeof declaredButNotAssigned); // => throws a ReferenceError - const declaredButNotAssigned = true; - } - ``` + // good + if (test) { + return false; + } - - - [14.2](#hoisting--anon-expressions) Anonymous function expressions hoist their variable name, but not the function assignment. + // bad + function foo() { + return false; + } - ```javascript - function example() { - console.log(anonymous); // => undefined + // good + function bar() { + return false; + } + ``` - anonymous(); // => TypeError anonymous is not a function + - var anonymous = function () { - console.log('anonymous function expression'); - }; - } - ``` +- [16.2](#blocks--cuddled-elses) If you’re using multiline blocks with `if` and `else`, put `else` on the same line as your `if` block’s closing brace. eslint: [`brace-style`](https://eslint.org/docs/rules/brace-style.html) - - - [14.3](#hoisting--named-expressions) Named function expressions hoist the variable name, not the function name or the function body. + ```javascript + // bad + if (test) { + thing1(); + thing2(); + } else { + thing3(); + } - ```javascript - function example() { - console.log(named); // => undefined + // good + if (test) { + thing1(); + thing2(); + } else { + thing3(); + } + ``` - named(); // => TypeError named is not a function + - superPower(); // => ReferenceError superPower is not defined +- [16.3](#blocks--no-else-return) If an `if` block always executes a `return` statement, the subsequent `else` block is unnecessary. A `return` in an `else if` block following an `if` block that contains a `return` can be separated into multiple `if` blocks. eslint: [`no-else-return`](https://eslint.org/docs/rules/no-else-return) - var named = function superPower() { - console.log('Flying'); - }; + ```javascript + // bad + function foo() { + if (x) { + return x; + } else { + return y; } + } - // the same is true when the function name - // is the same as the variable name. - function example() { - console.log(named); // => undefined + // bad + function cats() { + if (x) { + return x; + } else if (y) { + return y; + } + } - named(); // => TypeError named is not a function + // bad + function dogs() { + if (x) { + return x; + } else { + if (y) { + return y; + } + } + } - var named = function named() { - console.log('named'); - }; + // good + function foo() { + if (x) { + return x; } - ``` - - - [14.4](#hoisting--declarations) Function declarations hoist their name and the function body. + return y; + } + + // good + function cats() { + if (x) { + return x; + } - ```javascript - function example() { - superPower(); // => Flying + if (y) { + return y; + } + } - function superPower() { - console.log('Flying'); + // good + function dogs(x) { + if (x) { + if (z) { + return y; } + } else { + return z; } - ``` - - - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) by [Ben Cherry](http://www.adequatelygood.com/). + } + ``` **[⬆ back to top](#table-of-contents)** -## Comparison Operators & Equality - - - - [15.1](#comparison--eqeqeq) Use `===` and `!==` over `==` and `!=`. eslint: [`eqeqeq`](https://eslint.org/docs/rules/eqeqeq.html) +## Control Statements - - - [15.2](#comparison--if) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: + - - **Objects** evaluate to **true** - - **Undefined** evaluates to **false** - - **Null** evaluates to **false** - - **Booleans** evaluate to **the value of the boolean** - - **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** - - **Strings** evaluate to **false** if an empty string `''`, otherwise **true** +- [17.1](#control-statements) In case your control statement (`if`, `while` etc.) gets too long or exceeds the maximum line length, each (grouped) condition could be put into a new line. The logical operator should begin the line. - ```javascript - if ([0] && []) { - // true - // an array (even an empty one) is an object, objects will evaluate to true - } - ``` + > Why? Requiring operators at the beginning of the line keeps the operators aligned and follows a pattern similar to method chaining. This also improves readability by making it easier to visually follow complex logic. - - - [15.3](#comparison--shortcuts) Use shortcuts for booleans, but explicit comparisons for strings and numbers. + ```javascript + // bad + if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) { + thing1(); + } - ```javascript - // bad - if (isValid === true) { - // ... - } + // bad + if (foo === 123 && bar === 'abc') { + thing1(); + } - // good - if (isValid) { - // ... - } + // bad + if (foo === 123 && bar === 'abc') { + thing1(); + } - // bad - if (name) { - // ... - } + // bad + if (foo === 123 && bar === 'abc') { + thing1(); + } - // good - if (name !== '') { - // ... - } + // good + if (foo === 123 && bar === 'abc') { + thing1(); + } - // bad - if (collection.length) { - // ... - } + // good + if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) { + thing1(); + } - // good - if (collection.length > 0) { - // ... - } - ``` - - - - [15.4](#comparison--moreinfo) For more information see [Truth Equality and JavaScript](https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. - - - - [15.5](#comparison--switch-blocks) Use braces to create blocks in `case` and `default` clauses that contain lexical declarations (e.g. `let`, `const`, `function`, and `class`). eslint: [`no-case-declarations`](https://eslint.org/docs/rules/no-case-declarations.html) - - > Why? Lexical declarations are visible in the entire `switch` block but only get initialized when assigned, which only happens when its `case` is reached. This causes problems when multiple `case` clauses attempt to define the same thing. - - ```javascript - // bad - switch (foo) { - case 1: - let x = 1; - break; - case 2: - const y = 2; - break; - case 3: - function f() { - // ... - } - break; - default: - class C {} - } + // good + if (foo === 123 && bar === 'abc') { + thing1(); + } + ``` - // good - switch (foo) { - case 1: { - let x = 1; - break; - } - case 2: { - const y = 2; - break; - } - case 3: { - function f() { - // ... - } - break; - } - case 4: - bar(); - break; - default: { - class C {} - } - } - ``` - - - - [15.6](#comparison--nested-ternaries) Ternaries should not be nested and generally be single line expressions. eslint: [`no-nested-ternary`](https://eslint.org/docs/rules/no-nested-ternary.html) - - ```javascript - // bad - const foo = maybe1 > maybe2 - ? "bar" - : value1 > value2 ? "baz" : null; - - // split into 2 separated ternary expressions - const maybeNull = value1 > value2 ? 'baz' : null; - - // better - const foo = maybe1 > maybe2 - ? 'bar' - : maybeNull; - - // best - const foo = maybe1 > maybe2 ? 'bar' : maybeNull; - ``` - - - - [15.7](#comparison--unneeded-ternary) Avoid unneeded ternary statements. eslint: [`no-unneeded-ternary`](https://eslint.org/docs/rules/no-unneeded-ternary.html) - - ```javascript - // bad - const foo = a ? a : b; - const bar = c ? true : false; - const baz = c ? false : true; - - // good - const foo = a || b; - const bar = !!c; - const baz = !c; - ``` - - - - [15.8](#comparison--no-mixed-operators) When mixing operators, enclose them in parentheses. The only exception is the standard arithmetic operators: `+`, `-`, and `**` since their precedence is broadly understood. We recommend enclosing `/` and `*` in parentheses because their precedence can be ambiguous when they are mixed. - eslint: [`no-mixed-operators`](https://eslint.org/docs/rules/no-mixed-operators.html) + - > Why? This improves readability and clarifies the developer’s intention. +- [17.2](#control-statements--value-selection) Don't use selection operators in place of control statements. - ```javascript - // bad - const foo = a && b < 0 || c > 0 || d + 1 === 0; + ```javascript + // bad + !isRunning && startRunning(); - // bad - const bar = a ** b - 5 % d; + // good + if (!isRunning) { + startRunning(); + } + ``` - // bad - // one may be confused into thinking (a || b) && c - if (a || b && c) { - return d; - } +**[⬆ back to top](#table-of-contents)** - // bad - const bar = a + b / c * d; +## Comments - // good - const foo = (a && b < 0) || c > 0 || (d + 1 === 0); + - // good - const bar = a ** b - (5 % d); +- [18.1](#comments--multiline) Use `/** ... */` for multiline comments. - // good - if (a || (b && c)) { - return d; - } + ```javascript + // bad + // make() returns a new element + // based on the passed in tag name + // + // @param {String} tag + // @return {Element} element + function make(tag) { + // ... - // good - const bar = a + (b / c) * d; - ``` + return element; + } -**[⬆ back to top](#table-of-contents)** + // good + /** + * make() returns a new element + * based on the passed-in tag name + */ + function make(tag) { + // ... -## Blocks + return element; + } + ``` - - - [16.1](#blocks--braces) Use braces with all multiline blocks. eslint: [`nonblock-statement-body-position`](https://eslint.org/docs/rules/nonblock-statement-body-position) + - ```javascript - // bad - if (test) - return false; +- [18.2](#comments--singleline) Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block. - // good - if (test) return false; + ```javascript + // bad + const active = true; // is current tab - // good - if (test) { - return false; - } + // good + // is current tab + const active = true; - // bad - function foo() { return false; } + // bad + function getType() { + console.log('fetching type...'); + // set the default type to 'no type' + const type = this.type || 'no type'; - // good - function bar() { - return false; - } - ``` + return type; + } - - - [16.2](#blocks--cuddled-elses) If you’re using multiline blocks with `if` and `else`, put `else` on the same line as your `if` block’s closing brace. eslint: [`brace-style`](https://eslint.org/docs/rules/brace-style.html) + // good + function getType() { + console.log('fetching type...'); - ```javascript - // bad - if (test) { - thing1(); - thing2(); - } - else { - thing3(); - } + // set the default type to 'no type' + const type = this.type || 'no type'; - // good - if (test) { - thing1(); - thing2(); - } else { - thing3(); - } - ``` + return type; + } - - - [16.3](#blocks--no-else-return) If an `if` block always executes a `return` statement, the subsequent `else` block is unnecessary. A `return` in an `else if` block following an `if` block that contains a `return` can be separated into multiple `if` blocks. eslint: [`no-else-return`](https://eslint.org/docs/rules/no-else-return) + // also good + function getType() { + // set the default type to 'no type' + const type = this.type || 'no type'; - ```javascript - // bad - function foo() { - if (x) { - return x; - } else { - return y; - } - } + return type; + } + ``` - // bad - function cats() { - if (x) { - return x; - } else if (y) { - return y; - } - } + - // bad - function dogs() { - if (x) { - return x; - } else { - if (y) { - return y; - } - } - } +- [18.3](#comments--spaces) Start all comments with a space to make it easier to read. eslint: [`spaced-comment`](https://eslint.org/docs/rules/spaced-comment) - // good - function foo() { - if (x) { - return x; - } + ```javascript + // bad + //is current tab + const active = true; + + // good + // is current tab + const active = true; + + // bad + /** + *make() returns a new element + *based on the passed-in tag name + */ + function make(tag) { + // ... - return y; - } + return element; + } - // good - function cats() { - if (x) { - return x; - } + // good + /** + * make() returns a new element + * based on the passed-in tag name + */ + function make(tag) { + // ... - if (y) { - return y; - } - } + return element; + } + ``` - // good - function dogs(x) { - if (x) { - if (z) { - return y; - } - } else { - return z; - } - } - ``` + -**[⬆ back to top](#table-of-contents)** +- [18.4](#comments--actionitems) Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME: -- need to figure this out` or `TODO: -- need to implement`. -## Control Statements + - - - [17.1](#control-statements) In case your control statement (`if`, `while` etc.) gets too long or exceeds the maximum line length, each (grouped) condition could be put into a new line. The logical operator should begin the line. +- [18.5](#comments--fixme) Use `// FIXME:` to annotate problems. - > Why? Requiring operators at the beginning of the line keeps the operators aligned and follows a pattern similar to method chaining. This also improves readability by making it easier to visually follow complex logic. + ```javascript + class Calculator extends Abacus { + constructor() { + super(); - ```javascript - // bad - if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) { - thing1(); + // FIXME: shouldn’t use a global here + total = 0; } + } + ``` - // bad - if (foo === 123 && - bar === 'abc') { - thing1(); - } + - // bad - if (foo === 123 - && bar === 'abc') { - thing1(); - } +- [18.6](#comments--todo) Use `// TODO:` to annotate solutions to problems. - // bad - if ( - foo === 123 && - bar === 'abc' - ) { - thing1(); - } + ```javascript + class Calculator extends Abacus { + constructor() { + super(); - // good - if ( - foo === 123 - && bar === 'abc' - ) { - thing1(); + // TODO: total should be configurable by an options param + this.total = 0; } + } + ``` - // good - if ( - (foo === 123 || bar === 'abc') - && doesItLookGoodWhenItBecomesThatLong() - && isThisReallyHappening() - ) { - thing1(); - } +**[⬆ back to top](#table-of-contents)** - // good - if (foo === 123 && bar === 'abc') { - thing1(); - } - ``` +## Whitespace - - - [17.2](#control-statements--value-selection) Don't use selection operators in place of control statements. + - ```javascript - // bad - !isRunning && startRunning(); +- [19.1](#whitespace--spaces) Use soft tabs (space character) set to 2 spaces. eslint: [`indent`](https://eslint.org/docs/rules/indent.html) - // good - if (!isRunning) { - startRunning(); - } - ``` + ```javascript + // bad + function foo() { + ∙∙∙∙let name; + } -**[⬆ back to top](#table-of-contents)** + // bad + function bar() { + ∙let name; + } -## Comments + // good + function baz() { + ∙∙let name; + } + ``` - - - [18.1](#comments--multiline) Use `/** ... */` for multiline comments. + - ```javascript - // bad - // make() returns a new element - // based on the passed in tag name - // - // @param {String} tag - // @return {Element} element - function make(tag) { +- [19.2](#whitespace--before-blocks) Place 1 space before the leading brace. eslint: [`space-before-blocks`](https://eslint.org/docs/rules/space-before-blocks.html) - // ... + ```javascript + // bad + function test() { + console.log('test'); + } - return element; - } + // good + function test() { + console.log('test'); + } - // good - /** - * make() returns a new element - * based on the passed-in tag name - */ - function make(tag) { + // bad + dog.set('attr', { + age: '1 year', + breed: 'Bernese Mountain Dog', + }); + + // good + dog.set('attr', { + age: '1 year', + breed: 'Bernese Mountain Dog', + }); + ``` - // ... + - return element; - } - ``` +- [19.3](#whitespace--around-keywords) Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space between the argument list and the function name in function calls and declarations. eslint: [`keyword-spacing`](https://eslint.org/docs/rules/keyword-spacing.html) - - - [18.2](#comments--singleline) Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block. + ```javascript + // bad + if (isJedi) { + fight(); + } - ```javascript - // bad - const active = true; // is current tab + // good + if (isJedi) { + fight(); + } - // good - // is current tab - const active = true; + // bad + function fight() { + console.log('Swooosh!'); + } - // bad - function getType() { - console.log('fetching type...'); - // set the default type to 'no type' - const type = this.type || 'no type'; + // good + function fight() { + console.log('Swooosh!'); + } + ``` - return type; - } + - // good - function getType() { - console.log('fetching type...'); +- [19.4](#whitespace--infix-ops) Set off operators with spaces. eslint: [`space-infix-ops`](https://eslint.org/docs/rules/space-infix-ops.html) - // set the default type to 'no type' - const type = this.type || 'no type'; + ```javascript + // bad + const x = y + 5; - return type; - } + // good + const x = y + 5; + ``` - // also good - function getType() { - // set the default type to 'no type' - const type = this.type || 'no type'; + - return type; - } - ``` +- [19.5](#whitespace--newline-at-end) End files with a single newline character. eslint: [`eol-last`](https://github.com/eslint/eslint/blob/master/docs/rules/eol-last.md) - - - [18.3](#comments--spaces) Start all comments with a space to make it easier to read. eslint: [`spaced-comment`](https://eslint.org/docs/rules/spaced-comment) + ```javascript + // bad + import { es6 } from './AirbnbStyleGuide'; + // ... + export default es6; + ``` - ```javascript - // bad - //is current tab - const active = true; + ```javascript + // bad + import { es6 } from './AirbnbStyleGuide'; + // ... + export default es6;↵ + ↵ + ``` - // good - // is current tab - const active = true; + ```javascript + // good + import { es6 } from './AirbnbStyleGuide'; + // ... + export default es6;↵ + ``` - // bad - /** - *make() returns a new element - *based on the passed-in tag name - */ - function make(tag) { + - // ... +- [19.6](#whitespace--chains) Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which + emphasizes that the line is a method call, not a new statement. eslint: [`newline-per-chained-call`](https://eslint.org/docs/rules/newline-per-chained-call) [`no-whitespace-before-property`](https://eslint.org/docs/rules/no-whitespace-before-property) - return element; - } + ```javascript + // bad + $('#items').find('.selected').highlight().end().find('.open').updateCount(); + + // bad + $('#items').find('.selected').highlight().end().find('.open').updateCount(); + + // good + $('#items').find('.selected').highlight().end().find('.open').updateCount(); + + // bad + const leds = stage + .selectAll('.led') + .data(data) + .enter() + .append('svg:svg') + .classed('led', true) + .attr('width', (radius + margin) * 2) + .append('svg:g') + .attr('transform', `translate(${radius + margin},${radius + margin})`) + .call(tron.led); + + // good + const leds = stage + .selectAll('.led') + .data(data) + .enter() + .append('svg:svg') + .classed('led', true) + .attr('width', (radius + margin) * 2) + .append('svg:g') + .attr('transform', `translate(${radius + margin},${radius + margin})`) + .call(tron.led); + + // good + const leds = stage.selectAll('.led').data(data); + ``` - // good - /** - * make() returns a new element - * based on the passed-in tag name - */ - function make(tag) { + - // ... +- [19.7](#whitespace--after-blocks) Leave a blank line after blocks and before the next statement. - return element; - } - ``` + ```javascript + // bad + if (foo) { + return bar; + } + return baz; - - - [18.4](#comments--actionitems) Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME: -- need to figure this out` or `TODO: -- need to implement`. + // good + if (foo) { + return bar; + } - - - [18.5](#comments--fixme) Use `// FIXME:` to annotate problems. + return baz; - ```javascript - class Calculator extends Abacus { - constructor() { - super(); + // bad + const obj = { + foo() {}, + bar() {}, + }; + return obj; - // FIXME: shouldn’t use a global here - total = 0; - } - } - ``` + // good + const obj = { + foo() {}, - - - [18.6](#comments--todo) Use `// TODO:` to annotate solutions to problems. + bar() {}, + }; - ```javascript - class Calculator extends Abacus { - constructor() { - super(); + return obj; - // TODO: total should be configurable by an options param - this.total = 0; - } - } - ``` + // bad + const arr = [function foo() {}, function bar() {}]; + return arr; -**[⬆ back to top](#table-of-contents)** + // good + const arr = [function foo() {}, function bar() {}]; -## Whitespace + return arr; + ``` - - - [19.1](#whitespace--spaces) Use soft tabs (space character) set to 2 spaces. eslint: [`indent`](https://eslint.org/docs/rules/indent.html) + - ```javascript - // bad - function foo() { - ∙∙∙∙let name; - } +- [19.8](#whitespace--padded-blocks) Do not pad your blocks with blank lines. eslint: [`padded-blocks`](https://eslint.org/docs/rules/padded-blocks.html) - // bad - function bar() { - ∙let name; - } + ```javascript + // bad + function bar() { + console.log(foo); + } + + // bad + if (baz) { + console.log(qux); + } else { + console.log(foo); + } - // good - function baz() { - ∙∙let name; + // bad + class Foo { + constructor(bar) { + this.bar = bar; } - ``` + } - - - [19.2](#whitespace--before-blocks) Place 1 space before the leading brace. eslint: [`space-before-blocks`](https://eslint.org/docs/rules/space-before-blocks.html) + // good + function bar() { + console.log(foo); + } - ```javascript - // bad - function test(){ - console.log('test'); - } + // good + if (baz) { + console.log(qux); + } else { + console.log(foo); + } + ``` - // good - function test() { - console.log('test'); - } + - // bad - dog.set('attr',{ - age: '1 year', - breed: 'Bernese Mountain Dog', - }); +- [19.9](#whitespace--no-multiple-blanks) Do not use multiple blank lines to pad your code. eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines) - // good - dog.set('attr', { - age: '1 year', - breed: 'Bernese Mountain Dog', - }); - ``` + - - - [19.3](#whitespace--around-keywords) Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space between the argument list and the function name in function calls and declarations. eslint: [`keyword-spacing`](https://eslint.org/docs/rules/keyword-spacing.html) + ```javascript + // bad + class Person { + constructor(fullName, email, birthday) { + this.fullName = fullName; + + this.email = email; + + this.setAge(birthday); + } - ```javascript - // bad - if(isJedi) { - fight (); + setAge(birthday) { + const today = new Date(); + + const age = this.getAge(today, birthday); + + this.age = age; } - // good - if (isJedi) { - fight(); + getAge(today, birthday) { + // .. } + } - // bad - function fight () { - console.log ('Swooosh!'); + // good + class Person { + constructor(fullName, email, birthday) { + this.fullName = fullName; + this.email = email; + this.setAge(birthday); } - // good - function fight() { - console.log('Swooosh!'); + setAge(birthday) { + const today = new Date(); + const age = getAge(today, birthday); + this.age = age; } - ``` - - - [19.4](#whitespace--infix-ops) Set off operators with spaces. eslint: [`space-infix-ops`](https://eslint.org/docs/rules/space-infix-ops.html) + getAge(today, birthday) { + // .. + } + } + ``` - ```javascript - // bad - const x=y+5; + - // good - const x = y + 5; - ``` +- [19.10](#whitespace--in-parens) Do not add spaces inside parentheses. eslint: [`space-in-parens`](https://eslint.org/docs/rules/space-in-parens.html) - - - [19.5](#whitespace--newline-at-end) End files with a single newline character. eslint: [`eol-last`](https://github.com/eslint/eslint/blob/master/docs/rules/eol-last.md) + ```javascript + // bad + function bar(foo) { + return foo; + } - ```javascript - // bad - import { es6 } from './AirbnbStyleGuide'; - // ... - export default es6; - ``` + // good + function bar(foo) { + return foo; + } - ```javascript - // bad - import { es6 } from './AirbnbStyleGuide'; - // ... - export default es6;↵ - ↵ - ``` + // bad + if (foo) { + console.log(foo); + } - ```javascript - // good - import { es6 } from './AirbnbStyleGuide'; - // ... - export default es6;↵ - ``` - - - - [19.6](#whitespace--chains) Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which - emphasizes that the line is a method call, not a new statement. eslint: [`newline-per-chained-call`](https://eslint.org/docs/rules/newline-per-chained-call) [`no-whitespace-before-property`](https://eslint.org/docs/rules/no-whitespace-before-property) - - ```javascript - // bad - $('#items').find('.selected').highlight().end().find('.open').updateCount(); - - // bad - $('#items'). - find('.selected'). - highlight(). - end(). - find('.open'). - updateCount(); - - // good - $('#items') - .find('.selected') - .highlight() - .end() - .find('.open') - .updateCount(); - - // bad - const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) - .attr('width', (radius + margin) * 2).append('svg:g') - .attr('transform', `translate(${radius + margin},${radius + margin})`) - .call(tron.led); - - // good - const leds = stage.selectAll('.led') - .data(data) - .enter().append('svg:svg') - .classed('led', true) - .attr('width', (radius + margin) * 2) - .append('svg:g') - .attr('transform', `translate(${radius + margin},${radius + margin})`) - .call(tron.led); - - // good - const leds = stage.selectAll('.led').data(data); - ``` - - - - [19.7](#whitespace--after-blocks) Leave a blank line after blocks and before the next statement. - - ```javascript - // bad - if (foo) { - return bar; - } - return baz; + // good + if (foo) { + console.log(foo); + } + ``` - // good - if (foo) { - return bar; - } + - return baz; +- [19.11](#whitespace--in-brackets) Do not add spaces inside brackets. eslint: [`array-bracket-spacing`](https://eslint.org/docs/rules/array-bracket-spacing.html) - // bad - const obj = { - foo() { - }, - bar() { - }, - }; - return obj; + ```javascript + // bad + const foo = [1, 2, 3]; + console.log(foo[0]); - // good - const obj = { - foo() { - }, + // good + const foo = [1, 2, 3]; + console.log(foo[0]); + ``` - bar() { - }, - }; + - return obj; +- [19.12](#whitespace--in-braces) Add spaces inside curly braces. eslint: [`object-curly-spacing`](https://eslint.org/docs/rules/object-curly-spacing.html) - // bad - const arr = [ - function foo() { - }, - function bar() { - }, - ]; - return arr; + ```javascript + // bad + const foo = { clark: 'kent' }; - // good - const arr = [ - function foo() { - }, + // good + const foo = { clark: 'kent' }; + ``` - function bar() { - }, - ]; + - return arr; - ``` +- [19.13](#whitespace--max-len) Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per [above](#strings--line-length), long strings are exempt from this rule, and should not be broken up. eslint: [`max-len`](https://eslint.org/docs/rules/max-len.html) - - - [19.8](#whitespace--padded-blocks) Do not pad your blocks with blank lines. eslint: [`padded-blocks`](https://eslint.org/docs/rules/padded-blocks.html) + > Why? This ensures readability and maintainability. - ```javascript - // bad - function bar() { + ```javascript + // bad + const foo = + jsonData && + jsonData.foo && + jsonData.foo.bar && + jsonData.foo.bar.baz && + jsonData.foo.bar.baz.quux && + jsonData.foo.bar.baz.quux.xyzzy; + + // bad + $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }) + .done(() => console.log('Congratulations!')) + .fail(() => console.log('You have failed this city.')); + + // good + const foo = + jsonData && + jsonData.foo && + jsonData.foo.bar && + jsonData.foo.bar.baz && + jsonData.foo.bar.baz.quux && + jsonData.foo.bar.baz.quux.xyzzy; + + // good + $.ajax({ + method: 'POST', + url: 'https://airbnb.com/', + data: { name: 'John' }, + }) + .done(() => console.log('Congratulations!')) + .fail(() => console.log('You have failed this city.')); + ``` - console.log(foo); + - } +- [19.14](#whitespace--block-spacing) Require consistent spacing inside an open block token and the next token on the same line. This rule also enforces consistent spacing inside a close block token and previous token on the same line. eslint: [`block-spacing`](https://eslint.org/docs/rules/block-spacing) - // bad - if (baz) { + ```javascript + // bad + function foo() { + return true; + } + if (foo) { + bar = 0; + } - console.log(qux); - } else { - console.log(foo); + // good + function foo() { + return true; + } + if (foo) { + bar = 0; + } + ``` - } + - // bad - class Foo { +- [19.15](#whitespace--comma-spacing) Avoid spaces before commas and require a space after commas. eslint: [`comma-spacing`](https://eslint.org/docs/rules/comma-spacing) - constructor(bar) { - this.bar = bar; - } - } + ```javascript + // bad + var foo = 1, + bar = 2; + var arr = [1, 2]; + + // good + var foo = 1, + bar = 2; + var arr = [1, 2]; + ``` - // good - function bar() { - console.log(foo); - } + - // good - if (baz) { - console.log(qux); - } else { - console.log(foo); - } - ``` +- [19.16](#whitespace--computed-property-spacing) Enforce spacing inside of computed property brackets. eslint: [`computed-property-spacing`](https://eslint.org/docs/rules/computed-property-spacing) - - - [19.9](#whitespace--no-multiple-blanks) Do not use multiple blank lines to pad your code. eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines) + ```javascript + // bad + obj[foo]; + obj['foo']; + var x = { [b]: a }; + obj[foo[bar]]; + + // good + obj[foo]; + obj['foo']; + var x = { [b]: a }; + obj[foo[bar]]; + ``` - - ```javascript - // bad - class Person { - constructor(fullName, email, birthday) { - this.fullName = fullName; + +- [19.17](#whitespace--func-call-spacing) Avoid spaces between functions and their invocations. eslint: [`func-call-spacing`](https://eslint.org/docs/rules/func-call-spacing) - this.email = email; + ```javascript + // bad + func(); + func(); - this.setAge(birthday); - } + // good + func(); + ``` + - setAge(birthday) { - const today = new Date(); +- [19.18](#whitespace--key-spacing) Enforce spacing between keys and values in object literal properties. eslint: [`key-spacing`](https://eslint.org/docs/rules/key-spacing) + ```javascript + // bad + var obj = { foo: 42 }; + var obj2 = { foo: 42 }; - const age = this.getAge(today, birthday); + // good + var obj = { foo: 42 }; + ``` + - this.age = age; - } +- [19.19](#whitespace--no-trailing-spaces) Avoid trailing spaces at the end of lines. eslint: [`no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces) + - getAge(today, birthday) { - // .. - } - } +- [19.20](#whitespace--no-multiple-empty-lines) Avoid multiple empty lines, only allow one newline at the end of files, and avoid a newline at the beginning of files. eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines) - // good - class Person { - constructor(fullName, email, birthday) { - this.fullName = fullName; - this.email = email; - this.setAge(birthday); - } + - setAge(birthday) { - const today = new Date(); - const age = getAge(today, birthday); - this.age = age; - } + ```javascript + // bad - multiple empty lines + var x = 1; - getAge(today, birthday) { - // .. - } - } - ``` + var y = 2; - - - [19.10](#whitespace--in-parens) Do not add spaces inside parentheses. eslint: [`space-in-parens`](https://eslint.org/docs/rules/space-in-parens.html) + // bad - 2+ newlines at end of file + var x = 1; + var y = 2; - ```javascript - // bad - function bar( foo ) { - return foo; - } + // bad - 1+ newline(s) at beginning of file - // good - function bar(foo) { - return foo; - } + var x = 1; + var y = 2; - // bad - if ( foo ) { - console.log(foo); - } + // good + var x = 1; + var y = 2; + ``` - // good - if (foo) { - console.log(foo); - } - ``` - - - - [19.11](#whitespace--in-brackets) Do not add spaces inside brackets. eslint: [`array-bracket-spacing`](https://eslint.org/docs/rules/array-bracket-spacing.html) - - ```javascript - // bad - const foo = [ 1, 2, 3 ]; - console.log(foo[ 0 ]); - - // good - const foo = [1, 2, 3]; - console.log(foo[0]); - ``` - - - - [19.12](#whitespace--in-braces) Add spaces inside curly braces. eslint: [`object-curly-spacing`](https://eslint.org/docs/rules/object-curly-spacing.html) - - ```javascript - // bad - const foo = {clark: 'kent'}; - - // good - const foo = { clark: 'kent' }; - ``` - - - - [19.13](#whitespace--max-len) Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per [above](#strings--line-length), long strings are exempt from this rule, and should not be broken up. eslint: [`max-len`](https://eslint.org/docs/rules/max-len.html) - - > Why? This ensures readability and maintainability. - - ```javascript - // bad - const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; - - // bad - $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.')); - - // good - const foo = jsonData - && jsonData.foo - && jsonData.foo.bar - && jsonData.foo.bar.baz - && jsonData.foo.bar.baz.quux - && jsonData.foo.bar.baz.quux.xyzzy; + - // good - $.ajax({ - method: 'POST', - url: 'https://airbnb.com/', - data: { name: 'John' }, - }) - .done(() => console.log('Congratulations!')) - .fail(() => console.log('You have failed this city.')); - ``` +**[⬆ back to top](#table-of-contents)** - - - [19.14](#whitespace--block-spacing) Require consistent spacing inside an open block token and the next token on the same line. This rule also enforces consistent spacing inside a close block token and previous token on the same line. eslint: [`block-spacing`](https://eslint.org/docs/rules/block-spacing) +## Commas - ```javascript - // bad - function foo() {return true;} - if (foo) { bar = 0;} + - // good - function foo() { return true; } - if (foo) { bar = 0; } - ``` +- [20.1](#commas--leading-trailing) Leading commas: **Nope.** eslint: [`comma-style`](https://eslint.org/docs/rules/comma-style.html) - - - [19.15](#whitespace--comma-spacing) Avoid spaces before commas and require a space after commas. eslint: [`comma-spacing`](https://eslint.org/docs/rules/comma-spacing) + ```javascript + // bad + const story = [once, upon, aTime]; + + // good + const story = [once, upon, aTime]; + + // bad + const hero = { + firstName: 'Ada', + lastName: 'Lovelace', + birthYear: 1815, + superPower: 'computers', + }; + + // good + const hero = { + firstName: 'Ada', + lastName: 'Lovelace', + birthYear: 1815, + superPower: 'computers', + }; + ``` - ```javascript - // bad - var foo = 1,bar = 2; - var arr = [1 , 2]; + - // good - var foo = 1, bar = 2; - var arr = [1, 2]; - ``` +- [20.2](#commas--dangling) Additional trailing comma: **Yup.** eslint: [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle.html) - - - [19.16](#whitespace--computed-property-spacing) Enforce spacing inside of computed property brackets. eslint: [`computed-property-spacing`](https://eslint.org/docs/rules/computed-property-spacing) + > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don’t have to worry about the [trailing comma problem](https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas) in legacy browsers. - ```javascript - // bad - obj[foo ] - obj[ 'foo'] - var x = {[ b ]: a} - obj[foo[ bar ]] + ```diff + // bad - git diff without trailing comma + const hero = { + firstName: 'Florence', + - lastName: 'Nightingale' + + lastName: 'Nightingale', + + inventorOf: ['coxcomb chart', 'modern nursing'] + }; - // good - obj[foo] - obj['foo'] - var x = { [b]: a } - obj[foo[bar]] - ``` + // good - git diff with trailing comma + const hero = { + firstName: 'Florence', + lastName: 'Nightingale', + + inventorOf: ['coxcomb chart', 'modern nursing'], + }; + ``` - - - [19.17](#whitespace--func-call-spacing) Avoid spaces between functions and their invocations. eslint: [`func-call-spacing`](https://eslint.org/docs/rules/func-call-spacing) + ```javascript + // bad + const hero = { + firstName: 'Dana', + lastName: 'Scully', + }; - ```javascript - // bad - func (); + const heroes = ['Batman', 'Superman']; - func - (); + // good + const hero = { + firstName: 'Dana', + lastName: 'Scully', + }; - // good - func(); - ``` + const heroes = ['Batman', 'Superman']; - - - [19.18](#whitespace--key-spacing) Enforce spacing between keys and values in object literal properties. eslint: [`key-spacing`](https://eslint.org/docs/rules/key-spacing) + // bad + function createHero(firstName, lastName, inventorOf) { + // does nothing + } - ```javascript - // bad - var obj = { foo : 42 }; - var obj2 = { foo:42 }; + // good + function createHero(firstName, lastName, inventorOf) { + // does nothing + } - // good - var obj = { foo: 42 }; - ``` + // good (note that a comma must not appear after a "rest" element) + function createHero(firstName, lastName, inventorOf, ...heroArgs) { + // does nothing + } - - - [19.19](#whitespace--no-trailing-spaces) Avoid trailing spaces at the end of lines. eslint: [`no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces) + // bad + createHero(firstName, lastName, inventorOf); - - - [19.20](#whitespace--no-multiple-empty-lines) Avoid multiple empty lines, only allow one newline at the end of files, and avoid a newline at the beginning of files. eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines) + // good + createHero(firstName, lastName, inventorOf); - - ```javascript - // bad - multiple empty lines - var x = 1; + // good (note that a comma must not appear after a "rest" element) + createHero(firstName, lastName, inventorOf, ...heroArgs); + ``` +**[⬆ back to top](#table-of-contents)** - var y = 2; +## Semicolons - // bad - 2+ newlines at end of file - var x = 1; - var y = 2; + +- [21.1](#semicolons--required) **Yup.** eslint: [`semi`](https://eslint.org/docs/rules/semi.html) - // bad - 1+ newline(s) at beginning of file + > Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called [Automatic Semicolon Insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion) to determine whether or not it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues. - var x = 1; - var y = 2; + ```javascript + // bad - raises exception + const luke = {}; + const leia = {}[(luke, leia)].forEach((jedi) => (jedi.father = 'vader')); - // good - var x = 1; - var y = 2; + // bad - raises exception + const reaction = 'No! That’s impossible!'( + (async function meanwhileOnTheFalcon() { + // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` + // ... + })(), + ); - ``` - + // bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI! + function foo() { + return; + ('search your feelings, you know it to be foo'); + } -**[⬆ back to top](#table-of-contents)** + // good + const luke = {}; + const leia = {}; + [luke, leia].forEach((jedi) => { + jedi.father = 'vader'; + }); + + // good + const reaction = 'No! That’s impossible!'; + (async function meanwhileOnTheFalcon() { + // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` + // ... + })(); -## Commas + // good + function foo() { + return 'search your feelings, you know it to be foo'; + } + ``` - - - [20.1](#commas--leading-trailing) Leading commas: **Nope.** eslint: [`comma-style`](https://eslint.org/docs/rules/comma-style.html) - - ```javascript - // bad - const story = [ - once - , upon - , aTime - ]; - - // good - const story = [ - once, - upon, - aTime, - ]; - - // bad - const hero = { - firstName: 'Ada' - , lastName: 'Lovelace' - , birthYear: 1815 - , superPower: 'computers' - }; + [Read more](https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214#7365214). - // good - const hero = { - firstName: 'Ada', - lastName: 'Lovelace', - birthYear: 1815, - superPower: 'computers', - }; - ``` +**[⬆ back to top](#table-of-contents)** - - - [20.2](#commas--dangling) Additional trailing comma: **Yup.** eslint: [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle.html) +## Type Casting & Coercion - > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don’t have to worry about the [trailing comma problem](https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas) in legacy browsers. + - ```diff - // bad - git diff without trailing comma - const hero = { - firstName: 'Florence', - - lastName: 'Nightingale' - + lastName: 'Nightingale', - + inventorOf: ['coxcomb chart', 'modern nursing'] - }; +- [22.1](#coercion--explicit) Perform type coercion at the beginning of the statement. - // good - git diff with trailing comma - const hero = { - firstName: 'Florence', - lastName: 'Nightingale', - + inventorOf: ['coxcomb chart', 'modern nursing'], - }; - ``` + - ```javascript - // bad - const hero = { - firstName: 'Dana', - lastName: 'Scully' - }; +- [22.2](#coercion--strings) Strings: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) - const heroes = [ - 'Batman', - 'Superman' - ]; + ```javascript + // => this.reviewScore = 9; - // good - const hero = { - firstName: 'Dana', - lastName: 'Scully', - }; + // bad + const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string" - const heroes = [ - 'Batman', - 'Superman', - ]; - - // bad - function createHero( - firstName, - lastName, - inventorOf - ) { - // does nothing - } + // bad + const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf() - // good - function createHero( - firstName, - lastName, - inventorOf, - ) { - // does nothing - } + // bad + const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string - // good (note that a comma must not appear after a "rest" element) - function createHero( - firstName, - lastName, - inventorOf, - ...heroArgs - ) { - // does nothing - } + // good + const totalScore = String(this.reviewScore); + ``` - // bad - createHero( - firstName, - lastName, - inventorOf - ); - - // good - createHero( - firstName, - lastName, - inventorOf, - ); - - // good (note that a comma must not appear after a "rest" element) - createHero( - firstName, - lastName, - inventorOf, - ...heroArgs - ); - ``` + -**[⬆ back to top](#table-of-contents)** +- [22.3](#coercion--numbers) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. eslint: [`radix`](https://eslint.org/docs/rules/radix) [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) -## Semicolons + ```javascript + const inputValue = '4'; - - - [21.1](#semicolons--required) **Yup.** eslint: [`semi`](https://eslint.org/docs/rules/semi.html) + // bad + const val = new Number(inputValue); - > Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called [Automatic Semicolon Insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion) to determine whether or not it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues. + // bad + const val = +inputValue; - ```javascript - // bad - raises exception - const luke = {} - const leia = {} - [luke, leia].forEach((jedi) => jedi.father = 'vader') + // bad + const val = inputValue >> 0; - // bad - raises exception - const reaction = "No! That’s impossible!" - (async function meanwhileOnTheFalcon() { - // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` - // ... - }()) + // bad + const val = parseInt(inputValue); - // bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI! - function foo() { - return - 'search your feelings, you know it to be foo' - } + // good + const val = Number(inputValue); - // good - const luke = {}; - const leia = {}; - [luke, leia].forEach((jedi) => { - jedi.father = 'vader'; - }); + // good + const val = parseInt(inputValue, 10); + ``` - // good - const reaction = "No! That’s impossible!"; - (async function meanwhileOnTheFalcon() { - // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` - // ... - }()); + - // good - function foo() { - return 'search your feelings, you know it to be foo'; - } - ``` +- [22.4](#coercion--comment-deviations) If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](https://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you’re doing. - [Read more](https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214#7365214). + ```javascript + // good + /** + * parseInt was the reason my code was slow. + * Bitshifting the String to coerce it to a + * Number made it a lot faster. + */ + const val = inputValue >> 0; + ``` -**[⬆ back to top](#table-of-contents)** + -## Type Casting & Coercion +- [22.5](#coercion--bitwise) **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](https://es5.github.io/#x4.3.19), but bitshift operations always return a 32-bit integer ([source](https://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: - - - [22.1](#coercion--explicit) Perform type coercion at the beginning of the statement. + ```javascript + 2147483647 >> 0; // => 2147483647 + 2147483648 >> 0; // => -2147483648 + 2147483649 >> 0; // => -2147483647 + ``` - - - [22.2](#coercion--strings) Strings: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) + - ```javascript - // => this.reviewScore = 9; +- [22.6](#coercion--booleans) Booleans: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) - // bad - const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string" + ```javascript + const age = 0; - // bad - const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf() + // bad + const hasAge = new Boolean(age); - // bad - const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string + // good + const hasAge = Boolean(age); - // good - const totalScore = String(this.reviewScore); - ``` + // best + const hasAge = !!age; + ``` - - - [22.3](#coercion--numbers) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. eslint: [`radix`](https://eslint.org/docs/rules/radix) [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) +**[⬆ back to top](#table-of-contents)** - ```javascript - const inputValue = '4'; +## Naming Conventions - // bad - const val = new Number(inputValue); + - // bad - const val = +inputValue; +- [23.1](#naming--descriptive) Avoid single letter names. Be descriptive with your naming. eslint: [`id-length`](https://eslint.org/docs/rules/id-length) - // bad - const val = inputValue >> 0; + ```javascript + // bad + function q() { + // ... + } - // bad - const val = parseInt(inputValue); + // good + function query() { + // ... + } + ``` - // good - const val = Number(inputValue); + - // good - const val = parseInt(inputValue, 10); - ``` +- [23.2](#naming--camelCase) Use camelCase when naming objects, functions, and instances. eslint: [`camelcase`](https://eslint.org/docs/rules/camelcase.html) - - - [22.4](#coercion--comment-deviations) If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](https://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you’re doing. + ```javascript + // bad + const OBJEcttsssss = {}; + const this_is_my_object = {}; + function c() {} + + // good + const thisIsMyObject = {}; + function thisIsMyFunction() {} + ``` - ```javascript - // good - /** - * parseInt was the reason my code was slow. - * Bitshifting the String to coerce it to a - * Number made it a lot faster. - */ - const val = inputValue >> 0; - ``` + - - - [22.5](#coercion--bitwise) **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](https://es5.github.io/#x4.3.19), but bitshift operations always return a 32-bit integer ([source](https://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: +- [23.3](#naming--PascalCase) Use PascalCase only when naming constructors or classes. eslint: [`new-cap`](https://eslint.org/docs/rules/new-cap.html) - ```javascript - 2147483647 >> 0; // => 2147483647 - 2147483648 >> 0; // => -2147483648 - 2147483649 >> 0; // => -2147483647 - ``` + ```javascript + // bad + function user(options) { + this.name = options.name; + } - - - [22.6](#coercion--booleans) Booleans: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) + const bad = new user({ + name: 'nope', + }); - ```javascript - const age = 0; + // good + class User { + constructor(options) { + this.name = options.name; + } + } - // bad - const hasAge = new Boolean(age); + const good = new User({ + name: 'yup', + }); + ``` - // good - const hasAge = Boolean(age); + - // best - const hasAge = !!age; - ``` +- [23.4](#naming--leading-underscore) Do not use trailing or leading underscores. eslint: [`no-underscore-dangle`](https://eslint.org/docs/rules/no-underscore-dangle.html) -**[⬆ back to top](#table-of-contents)** + > Why? JavaScript does not have the concept of privacy in terms of properties or methods. Although a leading underscore is a common convention to mean “private”, in fact, these properties are fully public, and as such, are part of your public API contract. This convention might lead developers to wrongly think that a change won’t count as breaking, or that tests aren’t needed. tl;dr: if you want something to be “private”, it must not be observably present. -## Naming Conventions + ```javascript + // bad + this.__firstName__ = 'Panda'; + this.firstName_ = 'Panda'; + this._firstName = 'Panda'; + + // good + this.firstName = 'Panda'; + + // good, in environments where WeakMaps are available + // see https://kangax.github.io/compat-table/es6/#test-WeakMap + const firstNames = new WeakMap(); + firstNames.set(this, 'Panda'); + ``` - - - [23.1](#naming--descriptive) Avoid single letter names. Be descriptive with your naming. eslint: [`id-length`](https://eslint.org/docs/rules/id-length) + - ```javascript - // bad - function q() { - // ... - } +- [23.5](#naming--self-this) Don’t save references to `this`. Use arrow functions or [Function#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). - // good - function query() { - // ... - } - ``` + ```javascript + // bad + function foo() { + const self = this; + return function () { + console.log(self); + }; + } - - - [23.2](#naming--camelCase) Use camelCase when naming objects, functions, and instances. eslint: [`camelcase`](https://eslint.org/docs/rules/camelcase.html) + // bad + function foo() { + const that = this; + return function () { + console.log(that); + }; + } - ```javascript - // bad - const OBJEcttsssss = {}; - const this_is_my_object = {}; - function c() {} + // good + function foo() { + return () => { + console.log(this); + }; + } + ``` - // good - const thisIsMyObject = {}; - function thisIsMyFunction() {} - ``` + - - - [23.3](#naming--PascalCase) Use PascalCase only when naming constructors or classes. eslint: [`new-cap`](https://eslint.org/docs/rules/new-cap.html) +- [23.6](#naming--filename-matches-export) A base filename should exactly match the name of its default export. - ```javascript - // bad - function user(options) { - this.name = options.name; - } + ```javascript + // file 1 contents + class CheckBox { + // ... + } + export default CheckBox; + + // file 2 contents + export default function fortyTwo() { return 42; } + + // file 3 contents + export default function insideDirectory() {} + + // in some other file + // bad + import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename + import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export + import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export + + // bad + import CheckBox from './check_box'; // PascalCase import/export, snake_case filename + import forty_two from './forty_two'; // snake_case import/filename, camelCase export + import inside_directory from './inside_directory'; // snake_case import, camelCase export + import index from './inside_directory/index'; // requiring the index file explicitly + import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly + + // good + import CheckBox from './CheckBox'; // PascalCase export/import/filename + import fortyTwo from './fortyTwo'; // camelCase export/import/filename + import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index" + // ^ supports both insideDirectory.js and insideDirectory/index.js + ``` - const bad = new user({ - name: 'nope', - }); + - // good - class User { - constructor(options) { - this.name = options.name; - } - } +- [23.7](#naming--camelCase-default-export) Use camelCase when you export-default a function. Your filename should be identical to your function’s name. - const good = new User({ - name: 'yup', - }); - ``` - - - - [23.4](#naming--leading-underscore) Do not use trailing or leading underscores. eslint: [`no-underscore-dangle`](https://eslint.org/docs/rules/no-underscore-dangle.html) - - > Why? JavaScript does not have the concept of privacy in terms of properties or methods. Although a leading underscore is a common convention to mean “private”, in fact, these properties are fully public, and as such, are part of your public API contract. This convention might lead developers to wrongly think that a change won’t count as breaking, or that tests aren’t needed. tl;dr: if you want something to be “private”, it must not be observably present. - - ```javascript - // bad - this.__firstName__ = 'Panda'; - this.firstName_ = 'Panda'; - this._firstName = 'Panda'; - - // good - this.firstName = 'Panda'; - - // good, in environments where WeakMaps are available - // see https://kangax.github.io/compat-table/es6/#test-WeakMap - const firstNames = new WeakMap(); - firstNames.set(this, 'Panda'); - ``` - - - - [23.5](#naming--self-this) Don’t save references to `this`. Use arrow functions or [Function#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). - - ```javascript - // bad - function foo() { - const self = this; - return function () { - console.log(self); - }; - } + ```javascript + function makeStyleGuide() { + // ... + } - // bad - function foo() { - const that = this; - return function () { - console.log(that); - }; - } + export default makeStyleGuide; + ``` - // good - function foo() { - return () => { - console.log(this); - }; - } - ``` + - - - [23.6](#naming--filename-matches-export) A base filename should exactly match the name of its default export. +- [23.8](#naming--PascalCase-singleton) Use PascalCase when you export a constructor / class / singleton / function library / bare object. - ```javascript - // file 1 contents - class CheckBox { - // ... - } - export default CheckBox; - - // file 2 contents - export default function fortyTwo() { return 42; } - - // file 3 contents - export default function insideDirectory() {} - - // in some other file - // bad - import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename - import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export - import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export - - // bad - import CheckBox from './check_box'; // PascalCase import/export, snake_case filename - import forty_two from './forty_two'; // snake_case import/filename, camelCase export - import inside_directory from './inside_directory'; // snake_case import, camelCase export - import index from './inside_directory/index'; // requiring the index file explicitly - import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly - - // good - import CheckBox from './CheckBox'; // PascalCase export/import/filename - import fortyTwo from './fortyTwo'; // camelCase export/import/filename - import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index" - // ^ supports both insideDirectory.js and insideDirectory/index.js - ``` - - - - [23.7](#naming--camelCase-default-export) Use camelCase when you export-default a function. Your filename should be identical to your function’s name. - - ```javascript - function makeStyleGuide() { - // ... - } + ```javascript + const AirbnbStyleGuide = { + es6: {}, + }; - export default makeStyleGuide; - ``` + export default AirbnbStyleGuide; + ``` - - - [23.8](#naming--PascalCase-singleton) Use PascalCase when you export a constructor / class / singleton / function library / bare object. + - ```javascript - const AirbnbStyleGuide = { - es6: { - }, - }; +- [23.9](#naming--Acronyms-and-Initialisms) Acronyms and initialisms should always be all uppercased, or all lowercased. - export default AirbnbStyleGuide; - ``` + > Why? Names are for readability, not to appease a computer algorithm. - - - [23.9](#naming--Acronyms-and-Initialisms) Acronyms and initialisms should always be all uppercased, or all lowercased. + ```javascript + // bad + import SmsContainer from './containers/SmsContainer'; - > Why? Names are for readability, not to appease a computer algorithm. + // bad + const HttpRequests = [ + // ... + ]; - ```javascript - // bad - import SmsContainer from './containers/SmsContainer'; + // good + import SMSContainer from './containers/SMSContainer'; - // bad - const HttpRequests = [ - // ... - ]; + // good + const HTTPRequests = [ + // ... + ]; - // good - import SMSContainer from './containers/SMSContainer'; + // also good + const httpRequests = [ + // ... + ]; - // good - const HTTPRequests = [ - // ... - ]; + // best + import TextMessageContainer from './containers/TextMessageContainer'; - // also good - const httpRequests = [ - // ... - ]; + // best + const requests = [ + // ... + ]; + ``` - // best - import TextMessageContainer from './containers/TextMessageContainer'; + - // best - const requests = [ - // ... - ]; - ``` +- [23.10](#naming--uppercase) You may optionally uppercase a constant only if it (1) is exported, (2) is a `const` (it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change. - - - [23.10](#naming--uppercase) You may optionally uppercase a constant only if it (1) is exported, (2) is a `const` (it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change. + > Why? This is an additional tool to assist in situations where the programmer would be unsure if a variable might ever change. UPPERCASE_VARIABLES are letting the programmer know that they can trust the variable (and its properties) not to change. - > Why? This is an additional tool to assist in situations where the programmer would be unsure if a variable might ever change. UPPERCASE_VARIABLES are letting the programmer know that they can trust the variable (and its properties) not to change. - - What about all `const` variables? - This is unnecessary, so uppercasing should not be used for constants within a file. It should be used for exported constants however. - - What about exported objects? - Uppercase at the top level of export (e.g. `EXPORTED_OBJECT.key`) and maintain that all nested properties do not change. + - What about all `const` variables? - This is unnecessary, so uppercasing should not be used for constants within a file. It should be used for exported constants however. + - What about exported objects? - Uppercase at the top level of export (e.g. `EXPORTED_OBJECT.key`) and maintain that all nested properties do not change. - ```javascript - // bad - const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file'; + ```javascript + // bad + const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file'; - // bad - export const THING_TO_BE_CHANGED = 'should obviously not be uppercased'; + // bad + export const THING_TO_BE_CHANGED = 'should obviously not be uppercased'; - // bad - export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables'; + // bad + export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables'; - // --- + // --- - // allowed but does not supply semantic value - export const apiKey = 'SOMEKEY'; + // allowed but does not supply semantic value + export const apiKey = 'SOMEKEY'; - // better in most cases - export const API_KEY = 'SOMEKEY'; + // better in most cases + export const API_KEY = 'SOMEKEY'; - // --- + // --- - // bad - unnecessarily uppercases key while adding no semantic value - export const MAPPING = { - KEY: 'value' - }; + // bad - unnecessarily uppercases key while adding no semantic value + export const MAPPING = { + KEY: 'value', + }; - // good - export const MAPPING = { - key: 'value' - }; - ``` + // good + export const MAPPING = { + key: 'value', + }; + ``` **[⬆ back to top](#table-of-contents)** ## Accessors - - - [24.1](#accessors--not-required) Accessor functions for properties are not required. + - - - [24.2](#accessors--no-getters-setters) Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use `getVal()` and `setVal('hello')`. +- [24.1](#accessors--not-required) Accessor functions for properties are not required. - ```javascript - // bad - class Dragon { - get age() { - // ... - } - - set age(value) { - // ... - } - } + - // good - class Dragon { - getAge() { - // ... - } +- [24.2](#accessors--no-getters-setters) Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use `getVal()` and `setVal('hello')`. - setAge(value) { - // ... - } + ```javascript + // bad + class Dragon { + get age() { + // ... } - ``` - - - [24.3](#accessors--boolean-prefix) If the property/method is a `boolean`, use `isVal()` or `hasVal()`. + set age(value) { + // ... + } + } - ```javascript - // bad - if (!dragon.age()) { - return false; + // good + class Dragon { + getAge() { + // ... } - // good - if (!dragon.hasAge()) { - return false; + setAge(value) { + // ... } - ``` + } + ``` - - - [24.4](#accessors--consistent) It’s okay to create `get()` and `set()` functions, but be consistent. + - ```javascript - class Jedi { - constructor(options = {}) { - const lightsaber = options.lightsaber || 'blue'; - this.set('lightsaber', lightsaber); - } +- [24.3](#accessors--boolean-prefix) If the property/method is a `boolean`, use `isVal()` or `hasVal()`. - set(key, val) { - this[key] = val; - } + ```javascript + // bad + if (!dragon.age()) { + return false; + } - get(key) { - return this[key]; - } + // good + if (!dragon.hasAge()) { + return false; + } + ``` + + + +- [24.4](#accessors--consistent) It’s okay to create `get()` and `set()` functions, but be consistent. + + ```javascript + class Jedi { + constructor(options = {}) { + const lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); } - ``` + + set(key, val) { + this[key] = val; + } + + get(key) { + return this[key]; + } + } + ``` **[⬆ back to top](#table-of-contents)** ## Events - - - [25.1](#events--hash) When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass an object literal (also known as a "hash") instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: + - ```javascript - // bad - $(this).trigger('listingUpdated', listing.id); +- [25.1](#events--hash) When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass an object literal (also known as a "hash") instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: - // ... + ```javascript + // bad + $(this).trigger('listingUpdated', listing.id); - $(this).on('listingUpdated', (e, listingID) => { - // do something with listingID - }); - ``` + // ... - prefer: + $(this).on('listingUpdated', (e, listingID) => { + // do something with listingID + }); + ``` - ```javascript - // good - $(this).trigger('listingUpdated', { listingID: listing.id }); + prefer: - // ... + ```javascript + // good + $(this).trigger('listingUpdated', { listingID: listing.id }); - $(this).on('listingUpdated', (e, data) => { - // do something with data.listingID - }); - ``` + // ... + + $(this).on('listingUpdated', (e, data) => { + // do something with data.listingID + }); + ``` - **[⬆ back to top](#table-of-contents)** +**[⬆ back to top](#table-of-contents)** ## jQuery - - - [26.1](#jquery--dollar-prefix) Prefix jQuery object variables with a `$`. + - ```javascript - // bad - const sidebar = $('.sidebar'); +- [26.1](#jquery--dollar-prefix) Prefix jQuery object variables with a `$`. - // good - const $sidebar = $('.sidebar'); + ```javascript + // bad + const sidebar = $('.sidebar'); - // good - const $sidebarBtn = $('.sidebar-btn'); - ``` + // good + const $sidebar = $('.sidebar'); - - - [26.2](#jquery--cache) Cache jQuery lookups. + // good + const $sidebarBtn = $('.sidebar-btn'); + ``` - ```javascript - // bad - function setSidebar() { - $('.sidebar').hide(); + - // ... +- [26.2](#jquery--cache) Cache jQuery lookups. - $('.sidebar').css({ - 'background-color': 'pink', - }); - } + ```javascript + // bad + function setSidebar() { + $('.sidebar').hide(); - // good - function setSidebar() { - const $sidebar = $('.sidebar'); - $sidebar.hide(); + // ... - // ... + $('.sidebar').css({ + 'background-color': 'pink', + }); + } - $sidebar.css({ - 'background-color': 'pink', - }); - } - ``` + // good + function setSidebar() { + const $sidebar = $('.sidebar'); + $sidebar.hide(); + + // ... + + $sidebar.css({ + 'background-color': 'pink', + }); + } + ``` + + + +- [26.3](#jquery--queries) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) - - - [26.3](#jquery--queries) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) + - - - [26.4](#jquery--find) Use `find` with scoped jQuery object queries. +- [26.4](#jquery--find) Use `find` with scoped jQuery object queries. - ```javascript - // bad - $('ul', '.sidebar').hide(); + ```javascript + // bad + $('ul', '.sidebar').hide(); - // bad - $('.sidebar').find('ul').hide(); + // bad + $('.sidebar').find('ul').hide(); - // good - $('.sidebar ul').hide(); + // good + $('.sidebar ul').hide(); - // good - $('.sidebar > ul').hide(); + // good + $('.sidebar > ul').hide(); - // good - $sidebar.find('ul').hide(); - ``` + // good + $sidebar.find('ul').hide(); + ``` **[⬆ back to top](#table-of-contents)** ## ECMAScript 5 Compatibility - - - [27.1](#es5-compat--kangax) Refer to [Kangax](https://twitter.com/kangax/)’s ES5 [compatibility table](https://kangax.github.io/es5-compat-table/). + + +- [27.1](#es5-compat--kangax) Refer to [Kangax](https://twitter.com/kangax/)’s ES5 [compatibility table](https://kangax.github.io/es5-compat-table/). **[⬆ back to top](#table-of-contents)** + ## ECMAScript 6+ (ES 2015+) Styles - - - [28.1](#es6-styles) This is a collection of links to the various ES6+ features. + + +- [28.1](#es6-styles) This is a collection of links to the various ES6+ features. 1. [Arrow Functions](#arrow-functions) 1. [Classes](#classes--constructors) @@ -3640,50 +3720,53 @@ 1. [Iterators and Generators](#iterators-and-generators) 1. [Modules](#modules) - - - [28.2](#tc39-proposals) Do not use [TC39 proposals](https://github.com/tc39/proposals) that have not reached stage 3. + + +- [28.2](#tc39-proposals) Do not use [TC39 proposals](https://github.com/tc39/proposals) that have not reached stage 3. - > Why? [They are not finalized](https://tc39.github.io/process-document/), and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet. + > Why? [They are not finalized](https://tc39.github.io/process-document/), and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet. **[⬆ back to top](#table-of-contents)** ## Standard Library - The [Standard Library](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects) - contains utilities that are functionally broken but remain for legacy reasons. +The [Standard Library](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects) +contains utilities that are functionally broken but remain for legacy reasons. + + + +- [29.1](#standard-library--isnan) Use `Number.isNaN` instead of global `isNaN`. + eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals) - - - [29.1](#standard-library--isnan) Use `Number.isNaN` instead of global `isNaN`. - eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals) + > Why? The global `isNaN` coerces non-numbers to numbers, returning true for anything that coerces to NaN. + > If this behavior is desired, make it explicit. - > Why? The global `isNaN` coerces non-numbers to numbers, returning true for anything that coerces to NaN. - > If this behavior is desired, make it explicit. + ```javascript + // bad + isNaN('1.2'); // false + isNaN('1.2.3'); // true - ```javascript - // bad - isNaN('1.2'); // false - isNaN('1.2.3'); // true + // good + Number.isNaN('1.2.3'); // false + Number.isNaN(Number('1.2.3')); // true + ``` - // good - Number.isNaN('1.2.3'); // false - Number.isNaN(Number('1.2.3')); // true - ``` + - - - [29.2](#standard-library--isfinite) Use `Number.isFinite` instead of global `isFinite`. - eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals) +- [29.2](#standard-library--isfinite) Use `Number.isFinite` instead of global `isFinite`. + eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals) - > Why? The global `isFinite` coerces non-numbers to numbers, returning true for anything that coerces to a finite number. - > If this behavior is desired, make it explicit. + > Why? The global `isFinite` coerces non-numbers to numbers, returning true for anything that coerces to a finite number. + > If this behavior is desired, make it explicit. - ```javascript - // bad - isFinite('2e3'); // true + ```javascript + // bad + isFinite('2e3'); // true - // good - Number.isFinite('2e3'); // false - Number.isFinite(parseInt('2e3', 10)); // true - ``` + // good + Number.isFinite('2e3'); // false + Number.isFinite(parseInt('2e3', 10)); // true + ``` **[⬆ back to top](#table-of-contents)** diff --git a/ui/apps/pmm-app/config/jest-setup.ts b/ui/apps/pmm-app/config/jest-setup.ts index c444c5d93fe..6f42b79e3f5 100644 --- a/ui/apps/pmm-app/config/jest-setup.ts +++ b/ui/apps/pmm-app/config/jest-setup.ts @@ -1,7 +1,6 @@ -import '@testing-library/jest-dom' +import '@testing-library/jest-dom'; import { TextEncoder, TextDecoder } from 'util'; import 'jest-canvas-mock'; - -// Missing in jsdom -Object.assign(global, { TextDecoder, TextEncoder }); \ No newline at end of file +// Missing in jsdom +Object.assign(global, { TextDecoder, TextEncoder }); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts index 9b0aa3bc80a..79b3aaec827 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.constants.ts @@ -969,7 +969,7 @@ export const METRIC_CATALOGUE = { }, tmp_table_on_disk: { humanizeName: 'Tmp Table on Disk', - tooltipText: 'The query\'s temporary table was stored on disk', + tooltipText: "The query's temporary table was stored on disk", simpleName: 'tmp_table_on_disk', serviceTypes: [Databases.mysql], metricRelation: (data) => { @@ -1230,7 +1230,8 @@ export const METRIC_CATALOGUE = { }, locks_database_acquire_wait_count_read_shared: { humanizeName: 'Locks Database Acquire Wait Count Read Shared', - tooltipText: 'Number of times a read lock at the database level was requested but had to wait before being granted', + tooltipText: + 'Number of times a read lock at the database level was requested but had to wait before being granted', simpleName: 'locks_database_acquire_wait_count_read_shared', serviceTypes: [Databases.mongodb], metricRelation: (data) => { diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts index 95bf4321f13..d118abfc71f 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.styles.ts @@ -64,8 +64,8 @@ export const getStyles = stylesFactory((theme: GrafanaTheme, querySelected: bool .table-body, .table-body > div, - div:has([data-testid="table-loading"]), - [data-testid="table-loading"] { + div:has([data-testid='table-loading']), + [data-testid='table-loading'] { height: ${tableHeight}; max-height: ${tableHeight}; } diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts index b0e8306b6f2..2fc692afcf7 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.test.ts @@ -30,7 +30,8 @@ describe('QueryAnalytics.tools::', () => { }, })); const result = buildShareLink(1624401010000, 1642417914429); - const expected = 'https://localhost.com/graph?page_number=2&page_size=25&from=1624401010000&to=1642417914429&orgId=1'; + const expected = + 'https://localhost.com/graph?page_number=2&page_size=25&from=1624401010000&to=1642417914429&orgId=1'; expect(result).toBe(expected); }); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts index f9f10f1ad98..bf3be0d6fd8 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tools.ts @@ -3,22 +3,19 @@ import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from './QueryAnalytics.constant const hasAllValueOrText = (element) => element !== ALL_VARIABLE_VALUE && element !== ALL_VARIABLE_TEXT; -export const getLabelQueryParams = (labels) => Object.keys(labels) - .filter((key) => key !== 'interval') - .map((key) => ({ - key, - value: labels[key], - })) - .filter((item) => item.value.filter(hasAllValueOrText).length) || []; +export const getLabelQueryParams = (labels) => + Object.keys(labels) + .filter((key) => key !== 'interval') + .map((key) => ({ + key, + value: labels[key], + })) + .filter((item) => item.value.filter(hasAllValueOrText).length) || []; export const toUnixTimestamp = (date: string) => Math.floor(new Date(date).getTime()); export function buildShareLink(from: number, to: number) { - const { - origin, - pathname, - search, - } = window.location; + const { origin, pathname, search } = window.location; const baseUrl = origin + pathname; const params = new URLSearchParams(search.substring(1)); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx index f303c9864ac..b7b804d88ec 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/QueryAnalytics.tsx @@ -17,12 +17,7 @@ import { ConfigProvider } from 'antd'; import { getAntdTheme } from 'shared/core/theme'; import { applyPmmCssVariables } from 'shared/components/helpers/getPmmTheme'; import { QueryAnalyticsProvider, UrlParametersProvider } from './provider/provider'; -import { - Details, - Filters, - ManageColumns, - Overview, -} from './components'; +import { Details, Filters, ManageColumns, Overview } from './components'; import 'shared/styles.scss'; import 'shared/style.less'; import './qan.scss'; @@ -70,12 +65,7 @@ const QueryAnalyticsPanel: FC = ({ grafanaTheme }) => // Force remount when theme changes to ensure Ant Design components (Table, Select, Checkbox) // pick up the new theme from ConfigProvider. Without this, components render with wrong colors // until page refresh (e.g., dark mode Table in light theme). -
+
@@ -107,9 +97,7 @@ const QueryAnalyticsPanel: FC = ({ grafanaTheme }) => pane2Style={{ minHeight: '20%', zIndex: 999 }} > -
- {querySelected ?
: null} -
+
{querySelected ?
: null}
@@ -121,10 +109,7 @@ const QueryAnalyticsPanel: FC = ({ grafanaTheme }) => const QueryAnalyticsRoot: FC = (props) => { const grafanaTheme = useTheme(); - const antdTheme = useMemo( - () => getAntdTheme(grafanaTheme), - [grafanaTheme], - ); + const antdTheme = useMemo(() => getAntdTheme(grafanaTheme), [grafanaTheme]); // Apply CSS variables for QAN theme (dropdowns, backgrounds, text colors) // useLayoutEffect runs synchronously before browser paint, ensuring styles are applied before render diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx index cd513c8b794..7561c6bd050 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.tsx @@ -1,24 +1,22 @@ import React, { FC } from 'react'; import { Bar } from 'react-chartjs-2'; -import { - BarElement, CategoryScale, Chart as ChartJs, LinearScale, Tooltip, -} from 'chart.js'; +import { BarElement, CategoryScale, Chart as ChartJs, LinearScale, Tooltip } from 'chart.js'; import ChartDataLabels from 'chartjs-plugin-datalabels'; import { useTheme2 } from '@grafana/ui'; import { BarChartProps } from './BarChart.types'; import { getStyles } from './BarChart.styles'; import { getDefaultOptions } from './BarChart.utils'; -ChartJs.register( - CategoryScale, - LinearScale, - BarElement, - Tooltip, - ChartDataLabels, -); +ChartJs.register(CategoryScale, LinearScale, BarElement, Tooltip, ChartDataLabels); export const BarChart: FC = ({ - data, options: customOptions, width, height, orientation, barWidth, showLegend, + data, + options: customOptions, + width, + height, + orientation, + barWidth, + showLegend, }) => { const theme = useTheme2(); const styles = getStyles(height); @@ -34,14 +32,7 @@ export const BarChart: FC = ({ return (
- +
); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts index 013e2924b11..52604c5115b 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.types.ts @@ -2,8 +2,8 @@ import { ChartProps } from 'react-chartjs-2'; import { ChartData, ChartOptions } from 'chart.js'; import { GrafanaTheme2 } from '@grafana/data'; -export type BarChartOrientation = 'vertical'| 'horizontal'; -export interface BarChartProps extends Omit, 'type'>{ +export type BarChartOrientation = 'vertical' | 'horizontal'; +export interface BarChartProps extends Omit, 'type'> { orientation?: BarChartOrientation; barWidth?: number; showLegend?: boolean; @@ -16,4 +16,4 @@ export type GetDefaultOptionsProps = { barWidth?: number; showLegend?: boolean; theme: GrafanaTheme2; -} +}; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts index 31af445ca1e..b1d11595831 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/BarChart/BarChart.utils.ts @@ -2,9 +2,13 @@ import { ChartOptions } from 'chart.js'; import { GetDefaultOptionsProps } from './BarChart.types'; export const getDefaultOptions = ({ - options, orientation, barWidth, showLegend, theme, + options, + orientation, + barWidth, + showLegend, + theme, }: GetDefaultOptionsProps): ChartOptions<'bar'> => { - const indexAxis: 'x'|'y'| undefined = orientation && orientation === 'horizontal' ? 'y' : 'x'; + const indexAxis: 'x' | 'y' | undefined = orientation && orientation === 'horizontal' ? 'y' : 'x'; const defaultOptions = { indexAxis, @@ -67,8 +71,10 @@ export const getDefaultOptions = ({ }, }; - return options ? { - ...defaultOptions, - ...options, - } : defaultOptions; + return options + ? { + ...defaultOptions, + ...options, + } + : defaultOptions; }; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts index 9ec71629ffd..d1947b96c50 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.hooks.ts @@ -5,13 +5,7 @@ import { DatabasesType, QueryExampleResponseItem } from './Details.types'; export const useDetails = (): [boolean, QueryExampleResponseItem[], DatabasesType] => { const { - panelState: { - queryId, - groupBy, - from, - to, - labels, - }, + panelState: { queryId, groupBy, from, to, labels }, } = useContext(QueryAnalyticsProvider); const [loading, setLoading] = useState(false); const [examples, setExamples] = useState([]); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts index d469e99e5bc..14742572c01 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.messages.ts @@ -6,7 +6,7 @@ export const Messages = { cantExtractTables: 'No table info from example nor explain', noDataFound: 'No data found', closeDetails: 'Close', - isDML: 'Couldn\'t build explain with original query and it was replaced with equivalent SELECT query', + isDML: "Couldn't build explain with original query and it was replaced with equivalent SELECT query", tabs: { details: { tab: 'Details', diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts index 1f981d5f59f..ba50f4a4eb8 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.service.ts @@ -2,9 +2,7 @@ import { apiRequestQAN } from 'shared/components/helpers/api'; import { getLabelQueryParams } from 'pmm-qan/panel/QueryAnalytics.tools'; import { QueryExampleResponse } from './Details.types'; -const getExample = async ({ - filterBy, groupBy, labels = [], from, to, tables = [], -}) => { +const getExample = async ({ filterBy, groupBy, labels = [], from, to, tables = [] }) => { const data = { filter_by: filterBy, group_by: groupBy, diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx index 8ae024bf88b..e5307c3e9ea 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Details.tsx @@ -1,10 +1,6 @@ -import React, { - FC, useContext, useEffect, useState, -} from 'react'; +import React, { FC, useContext, useEffect, useState } from 'react'; import { QueryAnalyticsProvider } from 'pmm-qan/panel/provider/provider'; -import { - Button, Tab, TabContent, TabsBar, useTheme, -} from '@grafana/ui'; +import { Button, Tab, TabContent, TabsBar, useTheme } from '@grafana/ui'; import { cx } from '@emotion/css'; import { Scrollbar } from 'shared/components/Elements/Scrollbar/Scrollbar'; import { Databases } from 'shared/core'; @@ -27,9 +23,7 @@ export const DetailsSection: FC = () => { const styles = getStyles(theme); const { contextActions: { closeDetails, setActiveTab, setLoadingDetails }, - panelState: { - queryId, groupBy, totals, openDetailsTab, database, - }, + panelState: { queryId, groupBy, totals, openDetailsTab, database }, } = useContext(QueryAnalyticsProvider); const [loading, examples, databaseType] = useDetails(); @@ -80,14 +74,7 @@ export const DetailsSection: FC = () => { textMetrics={textMetrics} loading={metricsLoading} /> - {metadata - ? ( - - ) - : null} + {metadata ? : null} ), }, diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx index 8b642745bed..64a162f4b58 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.test.tsx @@ -6,7 +6,9 @@ import Example from './Example'; import { ExampleInterface } from './Example.types'; jest.mock('shared/components/helpers/notification-manager'); -jest.mock('@microlink/react-json-view', () => ({ src = {} }) =>
); +jest.mock('@microlink/react-json-view', () => ({ src = {} }) => ( +
+)); describe('Example tab page render test', () => { it('Component shows error text when there is no examples', () => { @@ -57,7 +59,8 @@ describe('Example tab page render test', () => { }, ], }; - const innerExample = '{"ns":"admin.system.version","op":"command","command":{"collStats":"system.version","scale":{"$numberInt":"1"},"lsid":{"id":{"$binary":{"base64":"7bcIiWGnQ7eH3G+AfVMdEA==","subType":"04"}}},"$clusterTime":{"clusterTime":{"$timestamp":{"t":1588860655,"i":1}},"signature":{"hash":{"$binary":{"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"00"}},"keyId":{"$numberLong":"0"}}},"$db":"admin","$readPreference":{"mode":"primaryPreferred"}}}'; + const innerExample = + '{"ns":"admin.system.version","op":"command","command":{"collStats":"system.version","scale":{"$numberInt":"1"},"lsid":{"id":{"$binary":{"base64":"7bcIiWGnQ7eH3G+AfVMdEA==","subType":"04"}}},"$clusterTime":{"clusterTime":{"$timestamp":{"t":1588860655,"i":1}},"signature":{"hash":{"$binary":{"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"00"}},"keyId":{"$numberLong":"0"}}},"$db":"admin","$readPreference":{"mode":"primaryPreferred"}}}'; const { container } = render(); expect(container.querySelector('.json')?.getAttribute('data-src')).toContain(innerExample); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx index 6635aea2214..332d50a8804 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tools.tsx @@ -5,20 +5,22 @@ import { Databases, logger } from 'shared/core'; import { Highlight } from 'shared/components/Hightlight/Highlight'; import ParseError from './ParseError/ParseError'; -export const getExample = (databaseType) => (example: any): any => { - if (databaseType === Databases.mongodb) { - try { - return ; - } catch (e) { - logger.error(e); - } +export const getExample = + (databaseType) => + (example: any): any => { + if (databaseType === Databases.mongodb) { + try { + return ; + } catch (e) { + logger.error(e); + } - return ; - } + return ; + } - return ( - - {sqlFormatter.format(example || '')} - - ); -}; + return ( + + {sqlFormatter.format(example || '')} + + ); + }; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx index 03470167adc..ec2fb1ec97a 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Example/Example.tsx @@ -12,9 +12,9 @@ const Example: FC = ({ databaseType, examples, loading }) => { {isExample && !loading ? examples - .filter(({ example }) => example) - .map((example) => example.example) - .map(getExample(databaseType)) + .filter(({ example }) => example) + .map((example) => example.example) + .map(getExample(databaseType)) : null} {!isExample ?
{Messages.noExamplesFound}
: null}
diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts index b90407a0d84..f92a75f5093 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/Explain.tools.ts @@ -23,15 +23,17 @@ export const processClassicExplain = (classic): ClassicExplainInterface => { .filter(Boolean) .map((title) => ({ Header: title, key: title, accessor: title })); - const rowsList = data.map((item) => item - .split('|') - .map((e) => (String(e) ? e.trim() : '')) - .filter(Boolean) - .reduce((acc, row, index) => { - acc[headerList[index].accessor] = row; - - return acc; - }, {})); + const rowsList = data.map((item) => + item + .split('|') + .map((e) => (String(e) ? e.trim() : '')) + .filter(Boolean) + .reduce((acc, row, index) => { + acc[headerList[index].accessor] = row; + + return acc; + }, {}), + ); return { columns: headerList, rows: rowsList }; }; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx index 9abbf1abfc4..9bbe8cd3be7 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Explain/components/ClassicExplain/ClassicExplain.tsx @@ -19,8 +19,7 @@ export const ClassicExplain = ({ classicExplain }) => { {classicExplain.error ?
{classicExplain.error}
: null} - {!classicExplain.error - && processedExplain.rows.length ? ( + {!classicExplain.error && processedExplain.rows.length ? (
{ noData={null} /> - ) : null} + ) : null} {!classicExplain.error && !processedExplain.rows.length ? (
{Messages.noClassicExplain}
) : null} diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx index cc165f0dced..a6a2cd41c29 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.tsx @@ -1,7 +1,5 @@ import React, { useMemo } from 'react'; -import { - Button, Field, Input, useStyles, -} from '@grafana/ui'; +import { Button, Field, Input, useStyles } from '@grafana/ui'; import { Form, Field as FinalField } from 'react-final-form'; import validators from 'shared/components/helpers/validators'; import { Messages } from './PlaceholdersForm.messages'; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts index f8059043bb3..086158eac40 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/PlaceholdersForm/PlaceholdersForm.utils.ts @@ -1,7 +1,8 @@ import { times } from 'lodash'; import { PlaceholderInput } from './PlaceholdersForm.types'; -export const prepareInputs = (count: number): PlaceholderInput[] => times(count, (idx) => ({ - label: `:${idx + 1}`, - fieldName: `placeholders.${idx}`, -})); +export const prepareInputs = (count: number): PlaceholderInput[] => + times(count, (idx) => ({ + label: `:${idx + 1}`, + fieldName: `placeholders.${idx}`, + })); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx index c53167dba17..e4957647f38 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/ExplainPlaceholders/QueryFingerprint/QueryFingerprint.test.tsx @@ -61,7 +61,7 @@ describe('QueryFingerprint component::', () => { render( , ); expect(screen.getByTestId('highlight-code').textContent).toEqual(QUERY_WITH_PLACEHOLDERS_FILLED); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts index ef11340e909..31252be1d4c 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.constants.ts @@ -1,5 +1,5 @@ // Part of names from https://github.com/percona/pmm/blob/main/dev/docs/managed/data-model.md -export const metadataNames: {[key: string]: {name: string}} = { +export const metadataNames: { [key: string]: { name: string } } = { service_name: { name: 'Service name', }, diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx index 3e8f813dd33..31a73cf3799 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metadata/Metadata.tsx @@ -41,11 +41,7 @@ const Metadata = ({ metadata, loading }) => { isOpen={metadataOpen} onToggle={() => setMetadataOpen((open) => !open)} > -
+
); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts index 7f1b6da8539..14f951de4c0 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.service.ts @@ -2,9 +2,7 @@ import { apiRequest } from 'shared/components/helpers/api'; import { getLabelQueryParams } from 'pmm-qan/panel/QueryAnalytics.tools'; import { HistogramRequest, HistogramResponse } from './Metrics.types'; -export const getMetrics = async ({ - filterBy, groupBy, labels = [], from, to, tables = [], totals, -}) => { +export const getMetrics = async ({ filterBy, groupBy, labels = [], from, to, tables = [], totals }) => { const body = { filter_by: filterBy || '', group_by: groupBy, @@ -18,9 +16,7 @@ export const getMetrics = async ({ return apiRequest.post('/v1/qan:getMetrics', body); }; -export const getHistogram = async ({ - queryId, labels = [], from, to, -}) => { +export const getHistogram = async ({ queryId, labels = [], from, to }) => { const body = { queryid: queryId, labels: getLabelQueryParams(labels), diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx index dcd2db043e0..874c569edd5 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/Metrics.tsx @@ -1,6 +1,4 @@ -import React, { - FC, useState, useRef, useEffect, -} from 'react'; +import React, { FC, useState, useRef, useEffect } from 'react'; import { Latency, Sparkline, TimeDistribution } from 'shared/components/Elements/Charts'; import { humanize } from 'shared/components/helpers/Humanization'; import { Overlay } from 'shared/components/Elements/Overlay/Overlay'; @@ -16,9 +14,7 @@ import { TopQuery } from '../TopQuery/TopQuery'; import { BarChart } from '../../BarChart/BarChart'; import { OVERLAY_LOADER_SIZE } from '../Details.constants'; -const Metrics: FC = ({ - databaseType, totals, metrics, textMetrics = {}, loading, groupBy, -}) => { +const Metrics: FC = ({ databaseType, totals, metrics, textMetrics = {}, loading, groupBy }) => { const styles = useStyles2(getStyles); const isHistogramAvailable = databaseType === Databases.postgresql && !totals && groupBy === 'queryid'; const [histogramData, histogramLoading] = useHistogram(isHistogramAvailable); @@ -38,9 +34,7 @@ const Metrics: FC = ({ ); const rateColumn = (totals) => (item) => { - const { - sparkline, metricName, isRate, units, metric, pipeTypes, - } = item; + const { sparkline, metricName, isRate, units, metric, pipeTypes } = item; const polygonChartProps = { data: sparkline, ykey: 'metric', @@ -51,9 +45,7 @@ const Metrics: FC = ({ return (
- {`${isRate ? humanize.transform(metric.rate, pipeTypes.ratePipe) : '0'} ${ - units - }`} + {`${isRate ? humanize.transform(metric.rate, pipeTypes.ratePipe) : '0'} ${units}`} {sparkline && }
@@ -143,11 +135,7 @@ const Metrics: FC = ({ isOpen={isTopQueryOpen} onToggle={() => setTopQueryVisibility(!isTopQueryOpen)} > - + ) : null} = ({
{isHistogramAvailable && histogramData && ( -
+
| undefined => { +export const getChartDataFromHistogramItems = ( + histogram_items: HistogramAPI[], + theme: GrafanaTheme2, +): ChartData<'bar'> | undefined => { if (histogram_items && histogram_items.length > 0) { const total = histogram_items.reduce( - (previousValue, { frequency }) => ( - frequency ? previousValue + frequency : previousValue - ), 0, + (previousValue, { frequency }) => (frequency ? previousValue + frequency : previousValue), + 0, ); const ranges = histogram_items.map(({ range }) => formatRange(range)); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts index 8740967bfa6..75dde988160 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/__mocks__/useHistogram.ts @@ -1,5 +1,3 @@ import { ChartData } from 'chart.js'; -export const useHistogram = (): [ChartData<'bar'>|undefined, boolean] => ([ - undefined, false, -]); +export const useHistogram = (): [ChartData<'bar'> | undefined, boolean] => [undefined, false]; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts index 878765c657b..1785a3281c2 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useHistogram.ts @@ -9,11 +9,9 @@ import { getChartDataFromHistogramItems } from '../Metrics.utils'; export const useHistogram = (isHistogramAvailable: boolean): [ChartData<'bar'> | undefined, boolean] => { const theme = useTheme2(); const { - panelState: { - queryId, from, to, labels, - }, + panelState: { queryId, from, to, labels }, } = useContext(QueryAnalyticsProvider); - const [data, setData] = useState|undefined>(); + const [data, setData] = useState | undefined>(); const [loading, setLoading] = useState(false); useEffect(() => { diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts index 97aa03401b2..ab47357e3af 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Metrics/hooks/useMetricDetails.ts @@ -8,9 +8,7 @@ import { TextMetrics } from '../Metrics.types'; export const useMetricsDetails = (): [any[], TextMetrics, boolean, string[]] => { const { contextActions, - panelState: { - queryId, groupBy, from, to, labels, totals, - }, + panelState: { queryId, groupBy, from, to, labels, totals }, } = useContext(QueryAnalyticsProvider); const [metrics, setMetrics] = useState([]); const [textMetrics, setTextMetrics] = useState({}); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts index a5d267c4455..bdb532e683b 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.hooks.ts @@ -5,7 +5,9 @@ import { PlanService } from './Plan.service'; import { QueryPlan } from './Plan.types'; export const usePlan = (): [QueryPlan | undefined, boolean] => { - const { panelState: { queryId } } = useContext(QueryAnalyticsProvider); + const { + panelState: { queryId }, + } = useContext(QueryAnalyticsProvider); const [plan, setPlan] = useState(); const [loading, setLoading] = useState(false); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts index 3ad61b37329..d5221ff87b4 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.service.ts @@ -9,8 +9,8 @@ export const PlanService = { return apiRequestQAN .get(`/query/${body.queryid}/plan`) - .then(({ planid, query_plan }) => ( - planid && query_plan ? { id: planid, plan: query_plan } : undefined - )); + .then(({ planid, query_plan }) => + planid && query_plan ? { id: planid, plan: query_plan } : undefined, + ); }, }; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx index 2af2164a8b5..c3666e22306 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Plan/Plan.tsx @@ -20,11 +20,7 @@ export const Plan: FC = () => { {plan?.plan || ''}
- +
diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts index 422cc754ec3..e53d5cb52bd 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.hooks.ts @@ -14,9 +14,7 @@ export const useTables = (example, explains, databaseType): any[] => { if (databaseType === Databases.mysql && jsonExplain.value) { const parsedJSON = JSON.parse(jsonExplain.value); - const realTableName = [ - get(parsedJSON, 'real_table_name'), - ].filter(Boolean); + const realTableName = [get(parsedJSON, 'real_table_name')].filter(Boolean); setTables(realTableName); } diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts index 89ae8f50797..bb3e0c9e08a 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tools.ts @@ -8,14 +8,16 @@ export const processTableData = (input): { columns: any[]; rows: any[] } => { .map((e) => (String(e) ? String(e).trim() : 'NULL')) .filter(Boolean) .map((title) => ({ Header: title, key: title, accessor: title })); - const rowsList = data.map((item) => item - .map((e) => (String(e) ? String(e).trim() : 'NULL')) - .filter(Boolean) - .reduce((acc, row, index) => { - acc[headerList[index].accessor] = row; + const rowsList = data.map((item) => + item + .map((e) => (String(e) ? String(e).trim() : 'NULL')) + .filter(Boolean) + .reduce((acc, row, index) => { + acc[headerList[index].accessor] = row; - return acc; - }, {})); + return acc; + }, {}), + ); return { columns: headerList, rows: rowsList }; }; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx index 54d0e97e51f..462c5f405fa 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/TableContainer.tsx @@ -1,7 +1,5 @@ import React, { FC, useEffect, useState } from 'react'; -import { - Collapse, Tab, TabContent, TabsBar, -} from '@grafana/ui'; +import { Collapse, Tab, TabContent, TabsBar } from '@grafana/ui'; import { Databases } from 'shared/core'; import { Messages } from 'pmm-qan/panel/components/Details/Details.messages'; import { TableCreate } from './components/TableCreate/TableCreate'; @@ -11,12 +9,7 @@ import { TableTabs } from './TableContainer.constants'; import { TableContainerProps } from './TableContainer.types'; import { useTables } from './TableContainer.hooks'; -const TableCreateContainer: FC = ({ - databaseType, - example, - database, - ...explains -}) => { +const TableCreateContainer: FC = ({ databaseType, example, database, ...explains }) => { const [tables] = useTables(example, explains, databaseType); const [isTableTableOpen, setTableTableOpen] = useState(true); const [isTableStatusOpen, setTableStatusOpen] = useState(true); @@ -80,9 +73,11 @@ const TableCreateContainer: FC = ({ ) : (
- {explains.classicExplain.error - ?
{explains.classicExplain.error}
- :
{Messages.cantExtractTables}
} + {explains.classicExplain.error ? ( +
{explains.classicExplain.error}
+ ) : ( +
{Messages.cantExtractTables}
+ )}
); }; diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx index 7e71918a388..99f4ae4b4da 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Indexes/Indexes.tsx @@ -5,9 +5,7 @@ import { Messages } from '../../../Details.messages'; import { TableProps } from '../Table.types'; import { useIndexes } from './Indexes.hooks'; -export const Indexes: FC = ({ - tableName, databaseType, example, database, -}) => { +export const Indexes: FC = ({ tableName, databaseType, example, database }) => { const [data, indexes] = useIndexes(databaseType, example, tableName, database); return ( diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx index 3f7a81e9990..22c032befae 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/Status/Status.tsx @@ -5,9 +5,7 @@ import { Messages } from '../../../Details.messages'; import { TableProps } from '../Table.types'; import { useTableStatus } from './Status.hooks'; -export const Status: FC = ({ - tableName, databaseType, example, database, -}) => { +export const Status: FC = ({ tableName, databaseType, example, database }) => { const [data, status] = useTableStatus(databaseType, example, tableName, database); return ( diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx index 0567040fbea..2690e70b267 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/Table/components/TableCreate/TableCreate.tsx @@ -4,9 +4,7 @@ import { Highlight } from 'shared/components/Hightlight/Highlight'; import { TableProps } from '../Table.types'; import { useShowCreateTable } from './TableCreate.hooks'; -export const TableCreate: FC = ({ - tableName, databaseType, example, database, -}) => { +export const TableCreate: FC = ({ tableName, databaseType, example, database }) => { const [showCreateTable] = useShowCreateTable(databaseType, example, tableName, database); return ( diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx index c4c0874a3ed..5dd051eea80 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.test.tsx @@ -9,11 +9,7 @@ jest.mock('shared/components/helpers/notification-manager'); describe('TopQuery::', () => { it('should render query and tooltip icon', () => { const { container, getByText } = render( - , + , ); expect(getByText('test')).not.toBeNull(); @@ -33,11 +29,7 @@ describe('TopQuery::', () => { }, }} > - + , ); diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx index 534139e608c..d7953c60b62 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Details/TopQuery/TopQuery.tsx @@ -6,11 +6,7 @@ import { QueryAnalyticsProvider } from 'pmm-qan/panel/provider/provider'; import { getStyles } from './TopQuery.styles'; import { TopQueryProps } from './TopQuery.types'; -export const TopQuery: FC = ({ - databaseType, - query, - queryId, -}) => { +export const TopQuery: FC = ({ databaseType, query, queryId }) => { const styles = useStyles(getStyles); const { contextActions } = useContext(QueryAnalyticsProvider); const selectQuery = useCallback(() => { diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts index 1ea18c60f15..1eb93181a54 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tools.ts @@ -1,7 +1,8 @@ import { getTemplateSrv } from '@grafana/runtime'; export const getSelectedCheckboxes = (filters, filtersGroups) => { - const selectedFilters = filtersGroups.map((group) => filters[group.dataKey]) + const selectedFilters = filtersGroups + .map((group) => filters[group.dataKey]) .filter(Boolean) .map((item) => item.name) .reduce((acc, item) => acc.concat(item), []) diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx index 03720c00075..e06e2580e0a 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/Filters.tsx @@ -1,6 +1,4 @@ -import React, { - FC, useEffect, useMemo, useRef, useState, -} from 'react'; +import React, { FC, useEffect, useMemo, useRef, useState } from 'react'; import { Form } from 'react-final-form'; import { cx } from '@emotion/css'; import { QueryAnalyticsProvider } from 'pmm-qan/panel/provider/provider'; @@ -76,21 +74,22 @@ export const Filters: FC = () => { ); const FilterInput = useMemo( - () => ({ filter }) => ( - } - placeholder="Filter by..." - data-testid="filters-search-field" - onChange={(e: React.FormEvent) => { - const element = e.target as HTMLInputElement; + () => + ({ filter }) => ( + } + placeholder="Filter by..." + data-testid="filters-search-field" + onChange={(e: React.FormEvent) => { + const element = e.target as HTMLInputElement; - setFilter(element.value); - e.stopPropagation(); - }} - value={filter} - className={styles.filtersField} - /> - ), + setFilter(element.value); + e.stopPropagation(); + }} + value={filter} + className={styles.filtersField} + /> + ), // eslint-disable-next-line react-hooks/exhaustive-deps [], ); @@ -110,10 +109,7 @@ export const Filters: FC = () => { setFilter(''); }} > -
+
diff --git a/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx index 88c605a60f2..63b0666a36a 100644 --- a/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx +++ b/ui/apps/pmm-app/src/pmm-qan/panel/components/Filters/components/CheckboxGroup/CheckboxGroup.tsx @@ -7,17 +7,15 @@ import { RawTimeRange } from '@grafana/data'; import { getStyles } from './CheckboxGroup.styles'; import { CheckboxGroupProps } from './CheckboxGroup.types'; -export const CheckboxGroup: FC = ( - { - name, - items, - group, - showAll, - filter: searchFilterBy, - getDashboardURL, - rawTime, - }, -) => { +export const CheckboxGroup: FC = ({ + name, + items, + group, + showAll, + filter: searchFilterBy, + getDashboardURL, + rawTime, +}) => { const theme = useTheme(); const styles = getStyles(theme); @@ -32,14 +30,14 @@ export const CheckboxGroup: FC = ( const searchFilter = (item) => { if (!item.value) { return ( - 'n/a'.includes(searchFilterBy.toLowerCase()) - || name.toLowerCase().includes(searchFilterBy.toLowerCase()) + 'n/a'.includes(searchFilterBy.toLowerCase()) || + name.toLowerCase().includes(searchFilterBy.toLowerCase()) ); } return ( - item.value.toLowerCase().includes(searchFilterBy.toLowerCase()) - || name.toLowerCase().includes(searchFilterBy.toLowerCase()) + item.value.toLowerCase().includes(searchFilterBy.toLowerCase()) || + name.toLowerCase().includes(searchFilterBy.toLowerCase()) ); }; @@ -56,10 +54,7 @@ export const CheckboxGroup: FC = ( {name} - + {`${filteredData.filter(searchFilter).length}`}

@@ -83,39 +78,34 @@ export const CheckboxGroup: FC = ( }; export interface FilterCheckboxProps { - hidden?: boolean, + hidden?: boolean; item: any; rawTime: RawTimeRange; group: string; getDashboardURL?: (value: string) => string; } -export const FilterCheckbox: FC = ( - { - hidden, - getDashboardURL, - item, - group, - rawTime, - }, -) => { +export const FilterCheckbox: FC = ({ + hidden, + getDashboardURL, + item, + group, + rawTime, +}) => { const theme = useTheme(); const styles = getStyles(theme); const valueExists = item.main_metric_percent !== undefined; - const dashboardURL = getDashboardURL && getDashboardURL(item.value) - ? `${getDashboardURL(item.value)}&from=${rawTime.from}&to=${rawTime.to}` - : ''; + const dashboardURL = + getDashboardURL && getDashboardURL(item.value) + ? `${getDashboardURL(item.value)}&from=${rawTime.from}&to=${rawTime.to}` + : ''; return ( -
@@ -71,17 +69,11 @@ const VerticalFieldLayout = ({ ); export const FormElement = (props) => { - const { - dataTestId, type, errors, alignLabel, - } = props; + const { dataTestId, type, errors, alignLabel } = props; return (
- {type === 'horizontal' ? ( - - ) : ( - - )} + {type === 'horizontal' ? : }
{errors} diff --git a/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx index 6ba8cdc3d39..8d862c41d6d 100644 --- a/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx +++ b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButton.test.tsx @@ -21,13 +21,21 @@ describe('RadioButton::', () => { }); it('Renders with active class', () => { - const { container } = render(Test); + const { container } = render( + + Test + , + ); expect(container.querySelector('label')?.className).toContain('active'); }); it('Renders with disabled class', () => { - const { container } = render(Test); + const { container } = render( + + Test + , + ); expect(container.querySelector('label')?.className).toContain('disabled'); }); diff --git a/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts index 9fd96cc8001..76f43268d7a 100644 --- a/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts +++ b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.styles.ts @@ -7,15 +7,15 @@ export const getStyles = stylesFactory((theme: GrafanaTheme) => { return { radioButtonGroup: css` - display: flex; - flex-direction: row; - flex-wrap: nowrap; - ${mq} { - flex-direction: column; - label { - justify-content: center; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + ${mq} { + flex-direction: column; + label { + justify-content: center; + } } - } - `, + `, }; }); diff --git a/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx index 0d59a48cd21..c30b0bf816a 100644 --- a/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx +++ b/ui/apps/pmm-app/src/shared/components/Form/Radio/RadioButtonGroup.tsx @@ -28,9 +28,10 @@ export const RadioButtonGroup: FC = ({ }) => { const theme = useTheme(); const styles = getStyles(theme); - const isActive = useCallback((key: string) => ( - selected ? key === selected : key === value - ), [selected, value]); + const isActive = useCallback( + (key: string) => (selected ? key === selected : key === value), + [selected, value], + ); return (
diff --git a/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.tsx b/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.tsx index 49050bf2c1a..bd2dde7897f 100644 --- a/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.tsx +++ b/ui/apps/pmm-app/src/shared/components/Hightlight/Highlight.tsx @@ -16,15 +16,8 @@ export const Highlight = ({ children, className, language }: HighlightProps) => }, [ref]); return ( -
-      
+    
+      
         {children}
       
     
diff --git a/ui/apps/pmm-app/src/shared/components/helpers/Helpers.tsx b/ui/apps/pmm-app/src/shared/components/helpers/Helpers.tsx index d830cc53bbc..5f6f71953db 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/Helpers.tsx +++ b/ui/apps/pmm-app/src/shared/components/helpers/Helpers.tsx @@ -15,11 +15,9 @@ interface PluginTooltipInterface { export const PluginTooltip = ({ text, links }: PluginTooltipInterface) => ( - {text} - {' '} -
+ {text}
{links.map((link) => ( ))} - )} + } style={{ background: 'deepskyblue' }} > diff --git a/ui/apps/pmm-app/src/shared/components/helpers/processMetrics.ts b/ui/apps/pmm-app/src/shared/components/helpers/processMetrics.ts index c1ac50e79ba..99822251c90 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/processMetrics.ts +++ b/ui/apps/pmm-app/src/shared/components/helpers/processMetrics.ts @@ -4,16 +4,17 @@ const getPercentOfTotal = (current, total) => { return +((+current[key] / +total[key]) * 100).toFixed(2); }; -const getSparkline = (sparklines, metricName) => sparklines.map((sparkline) => { - const key = Object.keys(sparkline).find((sparklineKey) => sparklineKey.includes(metricName)) as string; +const getSparkline = (sparklines, metricName) => + sparklines.map((sparkline) => { + const key = Object.keys(sparkline).find((sparklineKey) => sparklineKey.includes(metricName)) as string; - return { - point: sparkline.point, - time_frame: sparkline.time_frame, - timestamp: sparkline.timestamp, - [key]: sparkline[key], - }; -}); + return { + point: sparkline.point, + time_frame: sparkline.time_frame, + timestamp: sparkline.timestamp, + [key]: sparkline[key], + }; + }); const sortDetails = (a, b) => { const order = [ @@ -41,17 +42,14 @@ const sortDetails = (a, b) => { return indA < indB ? -1 : 1; }; -const metricHasData = ([, value]: [string, unknown]) => Object - .values(value as Record) - .some((value) => value !== 0); +const metricHasData = ([, value]: [string, unknown]) => + Object.values(value as Record).some((value) => value !== 0); export const processMetrics = (metricsCatalogue, metrics) => { const data = Object.keys(metrics.metrics).length ? metrics.metrics : metrics.totals; return Object.entries(data) - .filter( - (metricData) => Object.keys(metricData[1] as any[]).length, - ) + .filter((metricData) => Object.keys(metricData[1] as any[]).length) .filter(metricHasData) .sort(sortDetails) .map((metricData) => { diff --git a/ui/apps/pmm-app/src/shared/components/helpers/promises.test.tsx b/ui/apps/pmm-app/src/shared/components/helpers/promises.test.tsx index 95e7f1f3449..98a2c19d8e5 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/promises.test.tsx +++ b/ui/apps/pmm-app/src/shared/components/helpers/promises.test.tsx @@ -8,29 +8,20 @@ import { describe('processPromiseResults::', () => { it('should return array of fulfilled promise results', async () => { - const requests = [ - Promise.resolve(), - Promise.resolve(), - ]; + const requests = [Promise.resolve(), Promise.resolve()]; const results = await processPromiseResults(requests); expect(results.map(filterFulfilled).length).toBe(2); }); it('should return one fulfilled promise and two rejected', async () => { - const requests = [ - Promise.reject(), - Promise.resolve(), - Promise.reject(), - ]; + const requests = [Promise.reject(), Promise.resolve(), Promise.reject()]; const results = await processPromiseResults(requests); expect(results.filter(filterFulfilled).length).toBe(1); expect(results.filter(filterRejected).length).toBe(2); }); it('should return one fulfilled promise with value', async () => { - const requests = [ - Promise.resolve('done'), - ]; + const requests = [Promise.resolve('done')]; const results = await processPromiseResults(requests); const fulfilled = results.filter(filterFulfilled); @@ -40,10 +31,7 @@ describe('processPromiseResults::', () => { it('should return two rejected promises with value', async () => { const error1 = new Error('rejected 1'); const error2 = new Error('rejected 2'); - const requests = [ - Promise.reject(error1), - Promise.reject(error2), - ]; + const requests = [Promise.reject(error1), Promise.reject(error2)]; const results = await processPromiseResults(requests); const rejected = results.filter(filterRejected) as RejectedPromiseResult[]; diff --git a/ui/apps/pmm-app/src/shared/components/helpers/promises.ts b/ui/apps/pmm-app/src/shared/components/helpers/promises.ts index f44dbdae2cb..bbaabf97489 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/promises.ts +++ b/ui/apps/pmm-app/src/shared/components/helpers/promises.ts @@ -10,21 +10,24 @@ export interface RejectedPromiseResult { export type PromiseResult = FulfilledPromiseResult | RejectedPromiseResult; -export const processPromiseResults = (requests: Array>): Promise => Promise.all( - requests.map((promise) => promise - .then( - (value): FulfilledPromiseResult => ({ - status: 'fulfilled', - value, - }), - ) - .catch( - (reason): RejectedPromiseResult => ({ - status: 'rejected', - reason, - }), - )), -); +export const processPromiseResults = (requests: Array>): Promise => + Promise.all( + requests.map((promise) => + promise + .then( + (value): FulfilledPromiseResult => ({ + status: 'fulfilled', + value, + }), + ) + .catch( + (reason): RejectedPromiseResult => ({ + status: 'rejected', + reason, + }), + ), + ), + ); export const filterFulfilled = ({ status }: { status: PromiseResult['status'] }) => status === 'fulfilled'; export const filterRejected = ({ status }: { status: PromiseResult['status'] }) => status === 'rejected'; diff --git a/ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.ts b/ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.ts index 9dff4e5a602..02ea58f0610 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.ts +++ b/ui/apps/pmm-app/src/shared/components/helpers/time-parameters-parser.ts @@ -3,11 +3,12 @@ import moment from 'moment'; type TimeEdge = 'from' | 'to'; const getTimezone = () => { - const getCookie = (name) => document.cookie.split('; ').reduce((r, v) => { - const parts = v.split('='); + const getCookie = (name) => + document.cookie.split('; ').reduce((r, v) => { + const parts = v.split('='); - return parts[0] === name ? decodeURIComponent(parts[1]) : r; - }, ''); + return parts[0] === name ? decodeURIComponent(parts[1]) : r; + }, ''); return getCookie('timezone') || 'browser'; }; diff --git a/ui/apps/pmm-app/src/shared/components/helpers/validators.test.tsx b/ui/apps/pmm-app/src/shared/components/helpers/validators.test.tsx index 2bcc7fdf64f..4f03739a477 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/validators.test.tsx +++ b/ui/apps/pmm-app/src/shared/components/helpers/validators.test.tsx @@ -59,7 +59,7 @@ describe('Validate email', () => { expect(validators.validateEmail('test@example.org')).toBeUndefined(); expect(validators.validateEmail('test@example')).toBeUndefined(); expect(validators.validateEmail('someone@127.0.0.1')).toBeUndefined(); - expect(validators.validateEmail('!#$%&\'*+/=?^_`{|}~.-@com.com')).toBeUndefined(); + expect(validators.validateEmail("!#$%&'*+/=?^_`{|}~.-@com.com")).toBeUndefined(); expect(validators.validateEmail('te..st@example.com')).toBeUndefined(); }); @@ -169,8 +169,12 @@ describe('Validate min length', () => { it('Validator should return undefined if the passed value is invalid', () => { const testedLength = 8; - expect(validators.minLength(testedLength)('1234567')).toEqual(`Must contain at least ${testedLength} characters`); - expect(validators.minLength(testedLength)('0')).toEqual(`Must contain at least ${testedLength} characters`); + expect(validators.minLength(testedLength)('1234567')).toEqual( + `Must contain at least ${testedLength} characters`, + ); + expect(validators.minLength(testedLength)('0')).toEqual( + `Must contain at least ${testedLength} characters`, + ); }); }); diff --git a/ui/apps/pmm-app/src/shared/components/helpers/validators.ts b/ui/apps/pmm-app/src/shared/components/helpers/validators.ts index e3650aa2abb..6a511763420 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/validators.ts +++ b/ui/apps/pmm-app/src/shared/components/helpers/validators.ts @@ -38,15 +38,16 @@ export const validators = { }, validateEmail: (value: string) => { - const emailRe = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; + const emailRe = + /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; return emailRe.test(value) ? undefined : 'Invalid email address'; }, validateKeyValue: (value) => { if ( - value - && !value + value && + !value .split(/[\n\s]/) .filter(Boolean) .every((element) => /^[a-z0-9]+:[a-z0-9]+$/.test(element)) @@ -89,19 +90,21 @@ export const validators = { requiredTrue: (value: boolean) => (value === true ? undefined : 'Required field'), - compose: (...validators: Validator[]) => (value: any, values?: Record): VResult => { - let result: string | undefined; - - // eslint-disable-next-line no-restricted-syntax - for (const validator of validators) { - result = validator(value, values); - if (result !== undefined) { - break; + compose: + (...validators: Validator[]) => + (value: any, values?: Record): VResult => { + let result: string | undefined; + + // eslint-disable-next-line no-restricted-syntax + for (const validator of validators) { + result = validator(value, values); + if (result !== undefined) { + break; + } } - } - return result; - }, + return result; + }, }; export default validators; diff --git a/ui/apps/pmm-app/src/shared/core/Settings.service.ts b/ui/apps/pmm-app/src/shared/core/Settings.service.ts index e97570c7dc6..04970d23433 100644 --- a/ui/apps/pmm-app/src/shared/core/Settings.service.ts +++ b/ui/apps/pmm-app/src/shared/core/Settings.service.ts @@ -4,7 +4,7 @@ import { Settings, SettingsAPIResponse, SettingsPayload } from './types'; export const SettingsService = { async getSettings(): Promise { - const { settings } = await apiRequest.get(API.SETTINGS) as SettingsAPIResponse; + const { settings } = (await apiRequest.get(API.SETTINGS)) as SettingsAPIResponse; return toModel(settings); }, diff --git a/ui/apps/pmm-app/src/shared/core/logger.ts b/ui/apps/pmm-app/src/shared/core/logger.ts index 4845d5977fd..2568ade007e 100644 --- a/ui/apps/pmm-app/src/shared/core/logger.ts +++ b/ui/apps/pmm-app/src/shared/core/logger.ts @@ -11,13 +11,15 @@ enum LOG_LEVELS { NONE = 5, } -const truncate = (length = 30) => (str = '') => { - if (typeof str !== 'string') { - return str; - } +const truncate = + (length = 30) => + (str = '') => { + if (typeof str !== 'string') { + return str; + } - return `${str.substr(0, length - 3)}...`; -}; + return `${str.substr(0, length - 3)}...`; + }; let CONFIG_LOG_LEVEL: LOG_LEVELS = LOG_LEVELS.DEBUG; @@ -31,21 +33,20 @@ export const setLogLevel = (level: LOG_LEVELS) => { const LOG_LEVEL_KEYS = Object.keys(LOG_LEVELS).slice(5); -const createLogMethod = (loggerFunc: (...attrs: any[]) => void, level: LOG_LEVELS) => ( - first: any, - ...rest: any[] -) => { - if (level >= CONFIG_LOG_LEVEL) { - const key = LOG_LEVEL_KEYS[level]; - - console.group(`[${key}]`, truncate(50)(first)); - loggerFunc(first); - rest.forEach((paragraph) => { - loggerFunc(paragraph); - }); - console.groupEnd(); - } -}; +const createLogMethod = + (loggerFunc: (...attrs: any[]) => void, level: LOG_LEVELS) => + (first: any, ...rest: any[]) => { + if (level >= CONFIG_LOG_LEVEL) { + const key = LOG_LEVEL_KEYS[level]; + + console.group(`[${key}]`, truncate(50)(first)); + loggerFunc(first); + rest.forEach((paragraph) => { + loggerFunc(paragraph); + }); + console.groupEnd(); + } + }; export const logger = { debug: createLogMethod(console.debug, LOG_LEVELS.DEBUG), diff --git a/ui/apps/pmm-app/src/shared/core/theme.ts b/ui/apps/pmm-app/src/shared/core/theme.ts index 3b04ef7331b..3be0d31d3cc 100644 --- a/ui/apps/pmm-app/src/shared/core/theme.ts +++ b/ui/apps/pmm-app/src/shared/core/theme.ts @@ -105,6 +105,5 @@ export const antdLightTheme: ThemeConfig = { * @param grafanaTheme - The current Grafana theme * @returns AntD theme configuration for dark or light mode */ -export const getAntdTheme = (grafanaTheme: GrafanaTheme): ThemeConfig => ( - grafanaTheme.type === 'dark' ? antdDarkTheme : antdLightTheme -); +export const getAntdTheme = (grafanaTheme: GrafanaTheme): ThemeConfig => + grafanaTheme.type === 'dark' ? antdDarkTheme : antdLightTheme; From 164e2dfed6e130ee7565c07fd2e971da787680d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Silva?= Date: Thu, 30 Jul 2026 18:15:54 +0000 Subject: [PATCH 05/10] Fix remaining prettier drift against the pinned 3.8.1 (not 3.5.3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous formatting fix was run with prettier 3.5.3, matching package.json's ^3.5.3 range but not the version ui/yarn.lock actually resolves it to (3.8.1) — markdown formatting differs slightly between those versions for AGENTS.md and CODE-STYLE.md. --- ui/AGENTS.md | 2 +- ui/apps/pmm-app/CODE-STYLE.md | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ui/AGENTS.md b/ui/AGENTS.md index ae005472e72..9aa41c894d7 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -14,7 +14,7 @@ The UI uses a **Yarn workspaces + Turborepo** monorepo with four packages: | Package | Path | Purpose | | --------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **pmm** | `ui/apps/pmm/` | Main PMM UI application (Vite + React) | -| **pmm-compat** | `ui/apps/pmm-compat/` | Grafana plugin for PMM ↔ Grafana integration (Webpack) | +| **pmm-compat** | `ui/apps/pmm-compat/` | Grafana plugin for PMM ↔ Grafana integration (Webpack) | | **pmm-app** | `ui/apps/pmm-app/` | Grafana app plugin bundling PMM dashboards and the Query Analytics panel (Webpack). See [ui/apps/pmm-app/AGENTS.md](apps/pmm-app/AGENTS.md). Its `src/dashboards` is a symlink to the top-level `/dashboards` folder, the canonical source of dashboard JSON. | | **@pmm/shared** | `ui/packages/shared/` | Shared code: cross-frame messaging, types, utilities (Rollup) | diff --git a/ui/apps/pmm-app/CODE-STYLE.md b/ui/apps/pmm-app/CODE-STYLE.md index 461e6372e71..2270e7b17d1 100644 --- a/ui/apps/pmm-app/CODE-STYLE.md +++ b/ui/apps/pmm-app/CODE-STYLE.md @@ -41,7 +41,6 @@ - [1.1](#types--primitives) **Primitives**: When you access a primitive type you work directly on its value. - - `string` - `number` - `boolean` @@ -64,7 +63,6 @@ - [1.2](#types--complex) **Complex**: When you access a complex type you work on a reference to its value. - - `object` - `array` - `function` @@ -2020,7 +2018,6 @@ - [15.2](#comparison--if) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: - - **Objects** evaluate to **true** - **Undefined** evaluates to **false** - **Null** evaluates to **false** @@ -3474,7 +3471,6 @@ - [23.10](#naming--uppercase) You may optionally uppercase a constant only if it (1) is exported, (2) is a `const` (it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change. > Why? This is an additional tool to assist in situations where the programmer would be unsure if a variable might ever change. UPPERCASE_VARIABLES are letting the programmer know that they can trust the variable (and its properties) not to change. - - What about all `const` variables? - This is unnecessary, so uppercasing should not be used for constants within a file. It should be used for exported constants however. - What about exported objects? - Uppercase at the top level of export (e.g. `EXPORTED_OBJECT.key`) and maintain that all nested properties do not change. From ab7db6e76785f6943fdb0597f68e36ca74ceeb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Silva?= Date: Thu, 30 Jul 2026 18:35:54 +0000 Subject: [PATCH 06/10] Fix lint: disable Airbnb formatting rules that fight the pinned Prettier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Airbnb's ESLint config (which pmm-app extends) enables several stylistic rules (indent, operator-linebreak, implicit-arrow-linebreak, object-curly-newline, function-paren-newline, no-confusing-arrow, react/jsx-wrap-multilines, react/jsx-one-expression-per-line) that duplicate what Prettier already formats. These previously happened not to conflict because pmm-app's code had been formatted with an older Prettier; reformatting it with the workspace's pinned Prettier (3.8.1, see prior commits) exposed the conflict as 266 lint errors. eslint-config-prettier was already a devDependency but was never actually added to `extends` — add it (and its `prettier/react` companion, which disables the JSX-specific rules) last, so it wins. Also add `avoidEscape` to the `quotes` rule: Prettier intentionally uses double quotes for a string containing an apostrophe to avoid escaping it, which the plain `quotes: single` rule doesn't tolerate. Verified by running the actual pinned ESLint/plugin versions against every file the CI lint step had flagged: 0 errors remain. --- ui/apps/pmm-app/.eslintrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/apps/pmm-app/.eslintrc b/ui/apps/pmm-app/.eslintrc index 8d016c17b3b..2e7cb91a28b 100644 --- a/ui/apps/pmm-app/.eslintrc +++ b/ui/apps/pmm-app/.eslintrc @@ -1,5 +1,5 @@ { - "extends": ["./.config/.eslintrc", "plugin:react/recommended", "airbnb"], + "extends": ["./.config/.eslintrc", "plugin:react/recommended", "airbnb", "prettier", "prettier/react"], "env": { "jest/globals": true, "browser": true @@ -41,7 +41,7 @@ "react/display-name": ["off"], "max-len": ["error", { "code": 110, "ignoreStrings": true, "ignoreRegExpLiterals": true }], "prettier/prettier": ["off"], - "quotes": ["error", "single"], + "quotes": ["error", "single", { "avoidEscape": true }], "import/extensions": ["off"], "import/no-extraneous-dependencies": [ "error", From 1aa6d66b28285786c4e388193eb3bed95eb37b1e Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Fri, 31 Jul 2026 00:25:05 +0100 Subject: [PATCH 07/10] Fix pmm-app CI failures surfaced by joining the ui/ Yarn workspace - jest.config.js: resolve d3's dist bundle via its actual installed location instead of a hardcoded /node_modules path, which broke once d3 got hoisted to the workspace root. - ui/package.json: dedupe @types/jest (a wildcard "*" request from @types/testing-library__jest-dom was resolving a different, newer major version than pmm-app's own ^29.5.0), and pin react/react-dom consistently across the workspace. - pmm-app/package.json: bump @types/react and @types/react-dom to 18.x to match the actual React 18 runtime instead of the stale 16.x types left over from before the move. - pmm-app/tsconfig.json: widen typeRoots to also include the workspace-hoisted node_modules/@types, since pmm-app no longer has its own fully-populated local @types folder. - Modal.tsx: add the now-required explicit `children` prop (newer @types/react no longer implies it on FC). - Add types/react-table-config.d.ts: react-table's plugin hooks (e.g. useRowSelect) add instance properties TypeScript doesn't know about without this augmentation. - Update a stale Ant Design snapshot (adds an aria-describedby attribute from an upgraded tooltip dependency). Verified locally: format, lint, full test suite, and the full workspace build (pmm, pmm-compat, pmm-app) all pass clean. --- ui/apps/pmm-app/jest.config.js | 22 +- ui/apps/pmm-app/package.json | 8 +- .../components/Elements/Modal/Modal.tsx | 1 + .../__snapshots__/Helpers.test.tsx.snap | 1 + ui/apps/pmm-app/tsconfig.json | 2 +- ui/apps/pmm-app/types/react-table-config.d.ts | 9 + ui/package.json | 7 +- ui/yarn.lock | 3530 ++++++++++++++++- 8 files changed, 3362 insertions(+), 218 deletions(-) create mode 100644 ui/apps/pmm-app/types/react-table-config.d.ts diff --git a/ui/apps/pmm-app/jest.config.js b/ui/apps/pmm-app/jest.config.js index b3f8eb0c75b..f46d4074e54 100644 --- a/ui/apps/pmm-app/jest.config.js +++ b/ui/apps/pmm-app/jest.config.js @@ -1,9 +1,29 @@ // force timezone to UTC to allow tests to work regardless of local timezone // generally used by snapshots, but can affect specific tests +const path = require('path'); +const fs = require('fs'); const baseConfig = require('./.config/jest.config'); process.env.TZ = 'GMT'; +// d3's package.json "exports" map doesn't expose ./dist/d3.min.js as a subpath, and its +// install location varies with Yarn workspace hoisting, so resolve the package root by +// walking up from its entry point instead of assuming a fixed node_modules layout. +function resolvePackageRoot(pkgName) { + let dir = path.dirname(require.resolve(pkgName)); + for (;;) { + const pkgJsonPath = path.join(dir, 'package.json'); + if (fs.existsSync(pkgJsonPath) && JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')).name === pkgName) { + return dir; + } + const parent = path.dirname(dir); + if (parent === dir) { + throw new Error(`Could not resolve package root for ${pkgName}`); + } + dir = parent; + } +} + module.exports = { // Jest configuration provided by Grafana scaffolding ...baseConfig, @@ -19,6 +39,6 @@ module.exports = { ], moduleNameMapper: { ...baseConfig.moduleNameMapper, - d3: '/node_modules/d3/dist/d3.min.js', + d3: path.join(resolvePackageRoot('d3'), 'dist', 'd3.min.js'), }, }; diff --git a/ui/apps/pmm-app/package.json b/ui/apps/pmm-app/package.json index bfde8462f3f..e2d7aa0b96d 100644 --- a/ui/apps/pmm-app/package.json +++ b/ui/apps/pmm-app/package.json @@ -57,9 +57,9 @@ "lodash": "^4.17.23", "moment": "^2.29.4", "numeral": "^2.0.6", - "react": "18.2.0", + "react": "^18.3.1", "react-chartjs-2": "^4.0.1", - "react-dom": "18.2.0", + "react-dom": "^18.3.1", "react-final-form": "^6.5.3", "react-horizontal-stacked-bar-chart": "^8.15.2", "react-router-dom": "^6.22.0", @@ -94,8 +94,8 @@ "@types/lodash": "^4.14.194", "@types/mocha": "^8.0.3", "@types/node": "^20.8.7", - "@types/react": "^16.9.34", - "@types/react-dom": "^16.9.9", + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", "@types/react-router-dom": "^5.1.5", "@types/react-scrollbar": "^0.5.1", "@types/testing-library__jest-dom": "5.14.8", diff --git a/ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.tsx b/ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.tsx index 1a91eab5b5a..925db98f69c 100644 --- a/ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.tsx +++ b/ui/apps/pmm-app/src/shared/components/Elements/Modal/Modal.tsx @@ -9,6 +9,7 @@ interface ModalWindow { closeOnEscape?: boolean; isVisible: boolean; title: ReactNode | string; + children?: ReactNode; } export const Modal: FC = (props) => { diff --git a/ui/apps/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap b/ui/apps/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap index cc65a5c4a18..aa1cf35eff8 100644 --- a/ui/apps/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap +++ b/ui/apps/pmm-app/src/shared/components/helpers/__snapshots__/Helpers.test.tsx.snap @@ -3,6 +3,7 @@ exports[`PluginTooltip Renders with right props 1`] = ` extends UseRowSelectInstanceProps {} +} diff --git a/ui/package.json b/ui/package.json index 4bc63098d34..449667feab8 100644 --- a/ui/package.json +++ b/ui/package.json @@ -44,7 +44,12 @@ "immutable": "^5.1.5", "dompurify": "^3.2.7", "serialize-javascript": "^7.0.3", - "picomatch": "^4.0.4" + "picomatch": "^4.0.4", + "@types/jest": "^29.5.0", + "@types/react": "^18.3.2", + "@types/react-dom": "^18.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" }, "prettier": "@percona/prettier-config" } diff --git a/ui/yarn.lock b/ui/yarn.lock index 0861692a145..bc00d73d2a3 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -7,6 +7,89 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.4.tgz#2856c55443d3d461693f32d2b96fb6ea92e1ffa9" integrity sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg== +"@ant-design/colors@^7.0.0", "@ant-design/colors@^7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.2.1.tgz#3bbc1c6c18550020d1622a0067ff03492318df98" + integrity sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ== + dependencies: + "@ant-design/fast-color" "^2.0.6" + +"@ant-design/compatible@^5.1.3": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@ant-design/compatible/-/compatible-5.1.5.tgz#9ad71c661855828d787173f994da79c85050aaee" + integrity sha512-8ksVbT8rSBKWYYrtmWV6WnrmFYTp3FNRmHGXks8qVji3sZNdnBcLalmJsIPYkz+r2M8njckrsLZcUBvqxW2iCw== + dependencies: + "@ant-design/cssinjs" "^1.23.0" + "@ctrl/tinycolor" "^3.6.1" + classnames "^2.2.6" + dayjs "^1.11.4" + lodash.camelcase "^4.3.0" + lodash.upperfirst "^4.3.1" + rc-animate "^3.1.1" + rc-form "^2.4.12" + rc-util "^5.24.5" + +"@ant-design/css-animation@^1.7.2": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@ant-design/css-animation/-/css-animation-1.7.3.tgz#60a1c970014e86b28f940510d69e503e428f1136" + integrity sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA== + +"@ant-design/cssinjs-utils@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.3.tgz#5dd79126057920a6992d57b38dd84e2c0b707977" + integrity sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg== + dependencies: + "@ant-design/cssinjs" "^1.21.0" + "@babel/runtime" "^7.23.2" + rc-util "^5.38.0" + +"@ant-design/cssinjs@^1.21.0", "@ant-design/cssinjs@^1.23.0": + version "1.24.0" + resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.24.0.tgz#7db091f03f189abc77a13cbd27a2293802cd7285" + integrity sha512-K4cYrJBsgvL+IoozUXYjbT6LHHNt+19a9zkvpBPxLjFHas1UpPM2A5MlhROb0BT8N8WoavM5VsP9MeSeNK/3mg== + dependencies: + "@babel/runtime" "^7.11.1" + "@emotion/hash" "^0.8.0" + "@emotion/unitless" "^0.7.5" + classnames "^2.3.1" + csstype "^3.1.3" + rc-util "^5.35.0" + stylis "^4.3.4" + +"@ant-design/fast-color@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@ant-design/fast-color/-/fast-color-2.0.6.tgz#ab4d4455c1542c9017d367c2fa8ca3e4215d0ba2" + integrity sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA== + dependencies: + "@babel/runtime" "^7.24.7" + +"@ant-design/icons-svg@^4.4.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.5.0.tgz#7b1c567e489840d747f211d3688949bcba363ad2" + integrity sha512-1BTUFyKPTBZ53MuTP8s0k5SFEXL7o3VHEOwLgzaoWKwnBeqIcqUtVshc4SKzhI6uACfqhJqBwBUE9FsWR3uULA== + +"@ant-design/icons@^5.3.5", "@ant-design/icons@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-5.6.1.tgz#7290fcdc3d96ff3fca793ed399053cd29ad5dbd3" + integrity sha512-0/xS39c91WjPAZOWsvi1//zjx6kAp4kxWwctR6kuU6p133w8RU0D2dSCvZC19uQyharg/sAvYxGYWl01BbZZfg== + dependencies: + "@ant-design/colors" "^7.0.0" + "@ant-design/icons-svg" "^4.4.0" + "@babel/runtime" "^7.24.8" + classnames "^2.2.6" + rc-util "^5.31.1" + +"@ant-design/react-slick@~1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-1.1.2.tgz#f84ce3e4d0dc941f02b16f1d1d6d7a371ffbb4f1" + integrity sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA== + dependencies: + "@babel/runtime" "^7.10.4" + classnames "^2.2.5" + json2mq "^0.2.0" + resize-observer-polyfill "^1.5.1" + throttle-debounce "^5.0.0" + "@asamuzakjp/css-color@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@asamuzakjp/css-color/-/css-color-3.2.0.tgz#cc42f5b85c593f79f1fa4f25d2b9b321e61d1794" @@ -18,6 +101,13 @@ "@csstools/css-tokenizer" "^3.0.3" lru-cache "^10.4.3" +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.27.1", "@babel/code-frame@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7" @@ -27,11 +117,25 @@ js-tokens "^4.0.0" picocolors "^1.1.1" +"@babel/code-frame@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.7.tgz#f2fbbfea87c44a21590ec515b778b2c26d8866e7" + integrity sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw== + dependencies: + "@babel/helper-validator-identifier" "^7.29.7" + js-tokens "^4.0.0" + picocolors "^1.1.1" + "@babel/compat-data@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== +"@babel/compat-data@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629" + integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg== + "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.21.3", "@babel/core@^7.23.9": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f" @@ -53,6 +157,27 @@ json5 "^2.2.3" semver "^6.3.1" +"@babel/core@^7.21.4": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7" + integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA== + dependencies: + "@babel/code-frame" "^7.29.7" + "@babel/generator" "^7.29.7" + "@babel/helper-compilation-targets" "^7.29.7" + "@babel/helper-module-transforms" "^7.29.7" + "@babel/helpers" "^7.29.7" + "@babel/parser" "^7.29.7" + "@babel/template" "^7.29.7" + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/generator@^7.28.6", "@babel/generator@^7.7.2": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" @@ -64,6 +189,24 @@ "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" +"@babel/generator@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3" + integrity sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ== + dependencies: + "@babel/parser" "^7.29.7" + "@babel/types" "^7.29.7" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz#c70fe3c6ecbdc3fd2dd1b0f498428b88b82ce47f" + integrity sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw== + dependencies: + "@babel/types" "^7.29.7" + "@babel/helper-compilation-targets@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" @@ -75,11 +218,68 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz#7a1def704302401c47f64fa85589e974ae217042" + integrity sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g== + dependencies: + "@babel/compat-data" "^7.29.7" + "@babel/helper-validator-option" "^7.29.7" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz#6eddf286f2ec418f740c91d60a83347c55838ddd" + integrity sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.29.7" + "@babel/helper-member-expression-to-functions" "^7.29.7" + "@babel/helper-optimise-call-expression" "^7.29.7" + "@babel/helper-replace-supers" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + "@babel/traverse" "^7.29.7" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz#5d4c3f928f315cf6c4184ea2fc3b5b38745b2430" + integrity sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.29.7" + regexpu-core "^6.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz#cf1e4462b613f2b54c41e6ff758d5dfcaa2c85d1" + integrity sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA== + dependencies: + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + debug "^4.4.3" + lodash.debounce "^4.0.8" + resolve "^1.22.11" + "@babel/helper-globals@^7.28.0": version "7.28.0" resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== +"@babel/helper-globals@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b" + integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA== + +"@babel/helper-member-expression-to-functions@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz#8dbdb3ce0b5c487e1aec10e13c9a43a500814df8" + integrity sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg== + dependencies: + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" @@ -88,6 +288,14 @@ "@babel/traverse" "^7.28.6" "@babel/types" "^7.28.6" +"@babel/helper-module-imports@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz#ef25048a518e828d7393fac5882ddd73921d7396" + integrity sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g== + dependencies: + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/helper-module-transforms@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" @@ -97,16 +305,73 @@ "@babel/helper-validator-identifier" "^7.28.5" "@babel/traverse" "^7.28.6" +"@babel/helper-module-transforms@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae" + integrity sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg== + dependencies: + "@babel/helper-module-imports" "^7.29.7" + "@babel/helper-validator-identifier" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/helper-optimise-call-expression@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz#77b0b5b94f1997fa9d6e3125f445227b1faf9d85" + integrity sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong== + dependencies: + "@babel/types" "^7.29.7" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== +"@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz#c0a0766f1a13617d8a17407d7ab8f9d486225ea4" + integrity sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw== + +"@babel/helper-remap-async-to-generator@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz#34b1f68dd75b86d31df781a29c3ff2df88da82e6" + integrity sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og== + dependencies: + "@babel/helper-annotate-as-pure" "^7.29.7" + "@babel/helper-wrap-function" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/helper-replace-supers@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz#bc3c3964329043c79112e513c1b198f16589ac21" + integrity sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.29.7" + "@babel/helper-optimise-call-expression" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz#50c95c7e4c4f54936cfa0116428edc559862d551" + integrity sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ== + dependencies: + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/helper-string-parser@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== +"@babel/helper-string-parser@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f" + integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw== + +"@babel/helper-validator-identifier@^7.25.9", "@babel/helper-validator-identifier@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2" + integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg== + "@babel/helper-validator-identifier@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" @@ -117,6 +382,20 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== +"@babel/helper-validator-option@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a" + integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw== + +"@babel/helper-wrap-function@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz#eec72163044548a0935e9d182bf2d547ec5ff483" + integrity sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw== + dependencies: + "@babel/template" "^7.29.7" + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/helpers@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" @@ -125,6 +404,24 @@ "@babel/template" "^7.28.6" "@babel/types" "^7.28.6" +"@babel/helpers@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607" + integrity sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg== + dependencies: + "@babel/template" "^7.29.7" + "@babel/types" "^7.29.7" + +"@babel/highlight@^7.10.4": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.9.tgz#8141ce68fc73757946f983b343f1231f4691acc6" + integrity sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" @@ -132,6 +429,65 @@ dependencies: "@babel/types" "^7.28.6" +"@babel/parser@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334" + integrity sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg== + dependencies: + "@babel/types" "^7.29.7" + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz#2b535896d933a85aa92377eaa3d51a437d54a4e3" + integrity sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz#b00711a9e52bf4fe55ef7e54b2ef4a881bf804c8" + integrity sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz#2375328852026a3cf6bc0bcf2de7d236f2d5e701" + integrity sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz#759a857c46c4d2a6199685cf71070d81ae5f743a" + integrity sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz#86de98dd8e03836178231ea96c27dab26016a705" + integrity sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + "@babel/plugin-transform-optional-chaining" "^7.29.7" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz#f5d892681dbf4b08753436a5e55000d5ba728d6d" + integrity sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -160,6 +516,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-import-assertions@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz#c5cd868505269126cc18882e1f01f7b0e0e24b4e" + integrity sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-syntax-import-attributes@^7.24.7": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" @@ -167,6 +530,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.28.6" +"@babel/plugin-syntax-import-attributes@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz#6115264516e95ead0f35a41710906612e447f605" + integrity sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" @@ -251,11 +621,507 @@ dependencies: "@babel/helper-plugin-utils" "^7.28.6" +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz#d651343f562c03f47951bd1802195d0e10605f27" + integrity sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-async-generator-functions@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz#a5365617921d82a1fee33124a1102bb38a1e677d" + integrity sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-remap-async-to-generator" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-transform-async-to-generator@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz#3b5e8f1fb58133cf701bcf0baaf6f01bfd1a8889" + integrity sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w== + dependencies: + "@babel/helper-module-imports" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-remap-async-to-generator" "^7.29.7" + +"@babel/plugin-transform-block-scoped-functions@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz#96d292634434082d6687bcdb81139affedf77e8c" + integrity sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-block-scoping@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz#baa376691ae16244cd14335422fca6900f54e17d" + integrity sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-class-properties@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz#034897b8a21beec163332fac2de235b14409abdf" + integrity sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-class-static-block@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz#fed8efd19f3dd3e1114ee390707c70912778fd7c" + integrity sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-classes@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz#61d3e5aaae0c838acc3204d9db7c8dc05c25815b" + integrity sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.29.7" + "@babel/helper-compilation-targets" "^7.29.7" + "@babel/helper-globals" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-replace-supers" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-transform-computed-properties@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz#95028787ca31901b9a20b5c6d9605c32346f55ad" + integrity sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/template" "^7.29.7" + +"@babel/plugin-transform-destructuring@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz#5781ec6947852e27b64c1165f0db431f408090e4" + integrity sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-transform-dotall-regex@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz#b203de9740e4c7ff6b55ce436ed5313b88d70af8" + integrity sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-duplicate-keys@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz#8f3fe721835cb7a433420841dae90afc962ea7ae" + integrity sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz#dc6c405e55c01b7657e1827a25332c4ac17e9cac" + integrity sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-dynamic-import@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz#a83a6faec5bab5b619adf9d0eac6c1c270123c2a" + integrity sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-explicit-resource-management@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz#65c8b9f76ec915b02a0e1df703125a0fca58abaa" + integrity sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-transform-destructuring" "^7.29.7" + +"@babel/plugin-transform-exponentiation-operator@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz#00bf002fde8794356171f5d4df200f6bc0d5a303" + integrity sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-export-namespace-from@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz#d6014f45cec61d7691335c6c9804204bee801d51" + integrity sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-for-of@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz#c65a678592117717aacdb10c1b73a9cb85e830be" + integrity sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + +"@babel/plugin-transform-function-name@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz#8b87f8a7504dbcd96135167e3fc4f61126a7bd86" + integrity sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg== + dependencies: + "@babel/helper-compilation-targets" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-transform-json-strings@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz#f57d63dcc05b4481c281acedcd8fc4e3e439a1d4" + integrity sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-literals@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz#b90bd47463326c2a9d779e1bd5e1f88b9f421921" + integrity sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-logical-assignment-operators@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz#9b29425adf5c794967aabe4b046a046a167bac2f" + integrity sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-member-expression-literals@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz#1281689fa2fefc17b110d21ebafd0fe9402d5309" + integrity sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-modules-amd@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz#f05ca662c8a1dc4be2f337af9c7e80369c942d6c" + integrity sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew== + dependencies: + "@babel/helper-module-transforms" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-modules-commonjs@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz#70e6835abf2663dafbe94b8ef1f51de7351ef135" + integrity sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ== + dependencies: + "@babel/helper-module-transforms" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-modules-systemjs@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz#e575dd2ab9882906de120ff7dc9dee9914d8b6f3" + integrity sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ== + dependencies: + "@babel/helper-module-transforms" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-validator-identifier" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-transform-modules-umd@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz#391d1c0215aca6307257f2f608598dfe55feb6cf" + integrity sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA== + dependencies: + "@babel/helper-module-transforms" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz#21e75d847b31189842fa7a77703722ed4b43d27d" + integrity sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-new-target@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz#714147ce7947e1b49cbd84137ca2e75e92b2a067" + integrity sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz#8a54cdf88c3f50433a6173117a286195b67714cc" + integrity sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-numeric-separator@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz#0266d5cd42ab87ec40fee45a4e36483cfdcbc66a" + integrity sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-object-rest-spread@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz#e0d5060241803922c545676613cc8acbbda0d266" + integrity sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A== + dependencies: + "@babel/helper-compilation-targets" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-transform-destructuring" "^7.29.7" + "@babel/plugin-transform-parameters" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-transform-object-super@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz#e89283d14fa3c35817d4493ffc6bc649aa10e4eb" + integrity sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-replace-supers" "^7.29.7" + +"@babel/plugin-transform-optional-catch-binding@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz#729664f79985be504eba112c51de9f71d009030b" + integrity sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-optional-chaining@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz#b84a1b574b3c73001023092567e16c492b720e51" + integrity sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + +"@babel/plugin-transform-parameters@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz#a5ddc3b9bfb534814cb8334cbeba47d9cf9db090" + integrity sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-private-methods@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz#cea8bd3ab99533892897a02999d5b752584ad145" + integrity sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-private-property-in-object@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz#4a2f6be5aba47be7afbdb4cd7903c46edf3a7661" + integrity sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.29.7" + "@babel/helper-create-class-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-property-literals@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz#d45817cd72f9e134ab1f7fbb79264cfcb85cf636" + integrity sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-regenerator@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz#0f42626a7dbb0e7a7f52e036d3e43deebdc3ea4e" + integrity sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-regexp-modifiers@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz#68311c0c10af2198212528863f8542843e424025" + integrity sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-reserved-words@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz#a6feeb179b36a5f1fc6e3154c1eb727bdbe35876" + integrity sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-shorthand-properties@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz#25c0436b98f4bd9ca4b98e1fbd662743bbaab9bf" + integrity sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-spread@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz#a128bcdd6b5e5e47054907b2e50bc19c3f856edd" + integrity sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + +"@babel/plugin-transform-sticky-regex@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz#a42c0fd1fa42f7e98e1e0c7757f72a1bbca3a015" + integrity sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-template-literals@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz#ada97d8e0832bca8edb315888aa654b1570f3835" + integrity sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-typeof-symbol@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz#d848a4677c1ee3485ab017f4018f04597798911c" + integrity sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-unicode-escapes@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz#1e99554b0cddfd650d649a9f2b996049893e5720" + integrity sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-unicode-property-regex@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz#44444afc73768c2190fac4d95f7716817b7f204a" + integrity sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-unicode-regex@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz#c3064b293ff7f1794b71f7650eec8db9896d3e59" + integrity sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-unicode-sets-regex@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz#b03ac9f27326f6197e8e574add83bbf33fc34ecd" + integrity sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/preset-env@^7.21.4": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.29.7.tgz#5e2ab5e764b493fdefc99c43aeaa70a9533a37fd" + integrity sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA== + dependencies: + "@babel/compat-data" "^7.29.7" + "@babel/helper-compilation-targets" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-validator-option" "^7.29.7" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.29.7" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.29.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.29.7" + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array" "^7.29.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.29.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.29.7" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-import-assertions" "^7.29.7" + "@babel/plugin-syntax-import-attributes" "^7.29.7" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.29.7" + "@babel/plugin-transform-async-generator-functions" "^7.29.7" + "@babel/plugin-transform-async-to-generator" "^7.29.7" + "@babel/plugin-transform-block-scoped-functions" "^7.29.7" + "@babel/plugin-transform-block-scoping" "^7.29.7" + "@babel/plugin-transform-class-properties" "^7.29.7" + "@babel/plugin-transform-class-static-block" "^7.29.7" + "@babel/plugin-transform-classes" "^7.29.7" + "@babel/plugin-transform-computed-properties" "^7.29.7" + "@babel/plugin-transform-destructuring" "^7.29.7" + "@babel/plugin-transform-dotall-regex" "^7.29.7" + "@babel/plugin-transform-duplicate-keys" "^7.29.7" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.29.7" + "@babel/plugin-transform-dynamic-import" "^7.29.7" + "@babel/plugin-transform-explicit-resource-management" "^7.29.7" + "@babel/plugin-transform-exponentiation-operator" "^7.29.7" + "@babel/plugin-transform-export-namespace-from" "^7.29.7" + "@babel/plugin-transform-for-of" "^7.29.7" + "@babel/plugin-transform-function-name" "^7.29.7" + "@babel/plugin-transform-json-strings" "^7.29.7" + "@babel/plugin-transform-literals" "^7.29.7" + "@babel/plugin-transform-logical-assignment-operators" "^7.29.7" + "@babel/plugin-transform-member-expression-literals" "^7.29.7" + "@babel/plugin-transform-modules-amd" "^7.29.7" + "@babel/plugin-transform-modules-commonjs" "^7.29.7" + "@babel/plugin-transform-modules-systemjs" "^7.29.7" + "@babel/plugin-transform-modules-umd" "^7.29.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.29.7" + "@babel/plugin-transform-new-target" "^7.29.7" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.29.7" + "@babel/plugin-transform-numeric-separator" "^7.29.7" + "@babel/plugin-transform-object-rest-spread" "^7.29.7" + "@babel/plugin-transform-object-super" "^7.29.7" + "@babel/plugin-transform-optional-catch-binding" "^7.29.7" + "@babel/plugin-transform-optional-chaining" "^7.29.7" + "@babel/plugin-transform-parameters" "^7.29.7" + "@babel/plugin-transform-private-methods" "^7.29.7" + "@babel/plugin-transform-private-property-in-object" "^7.29.7" + "@babel/plugin-transform-property-literals" "^7.29.7" + "@babel/plugin-transform-regenerator" "^7.29.7" + "@babel/plugin-transform-regexp-modifiers" "^7.29.7" + "@babel/plugin-transform-reserved-words" "^7.29.7" + "@babel/plugin-transform-shorthand-properties" "^7.29.7" + "@babel/plugin-transform-spread" "^7.29.7" + "@babel/plugin-transform-sticky-regex" "^7.29.7" + "@babel/plugin-transform-template-literals" "^7.29.7" + "@babel/plugin-transform-typeof-symbol" "^7.29.7" + "@babel/plugin-transform-unicode-escapes" "^7.29.7" + "@babel/plugin-transform-unicode-property-regex" "^7.29.7" + "@babel/plugin-transform-unicode-regex" "^7.29.7" + "@babel/plugin-transform-unicode-sets-regex" "^7.29.7" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.15" + babel-plugin-polyfill-corejs3 "^0.14.0" + babel-plugin-polyfill-regenerator "^0.6.6" + core-js-compat "^3.48.0" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.1", "@babel/runtime@^7.12.0", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.23.2", "@babel/runtime@^7.24.5", "@babel/runtime@^7.27.6", "@babel/runtime@^7.7.6", "@babel/runtime@^7.9.2": version "7.28.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.3.tgz#75c5034b55ba868121668be5d5bb31cc64e6e61a" integrity sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA== +"@babel/runtime@^7.10.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.2", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.26.0": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768" + integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw== + "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.25.7", "@babel/runtime@^7.26.7", "@babel/runtime@^7.28.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" @@ -270,6 +1136,15 @@ "@babel/parser" "^7.28.6" "@babel/types" "^7.28.6" +"@babel/template@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700" + integrity sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg== + dependencies: + "@babel/code-frame" "^7.29.7" + "@babel/parser" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/traverse@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e" @@ -283,6 +1158,19 @@ "@babel/types" "^7.28.6" debug "^4.3.1" +"@babel/traverse@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d" + integrity sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw== + dependencies: + "@babel/code-frame" "^7.29.7" + "@babel/generator" "^7.29.7" + "@babel/helper-globals" "^7.29.7" + "@babel/parser" "^7.29.7" + "@babel/template" "^7.29.7" + "@babel/types" "^7.29.7" + debug "^4.3.1" + "@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.3.3": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df" @@ -291,6 +1179,14 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" +"@babel/types@^7.29.7", "@babel/types@^7.4.4": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92" + integrity sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA== + dependencies: + "@babel/helper-string-parser" "^7.29.7" + "@babel/helper-validator-identifier" "^7.29.7" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -336,6 +1232,11 @@ resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3" integrity sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw== +"@ctrl/tinycolor@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31" + integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA== + "@date-fns/tz@^1.4.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@date-fns/tz/-/tz-1.4.1.tgz#2d905f282304630e07bef6d02d2e7dbf3f0cc4e4" @@ -396,6 +1297,11 @@ "@emotion/sheet" "^1.4.0" "@emotion/utils" "^1.4.2" +"@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/hash@^0.9.2": version "0.9.2" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" @@ -460,6 +1366,11 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== +"@emotion/unitless@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + "@emotion/use-insertion-effect-with-fallbacks@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz#8a8cb77b590e09affb960f4ff1e9a89e532738bf" @@ -475,6 +1386,15 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== +"@es-joy/jsdoccomment@~0.40.1": + version "0.40.1" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.40.1.tgz#13acd77fb372ed1c83b7355edd865a3b370c9ec4" + integrity sha512-YORCdZSusAlBrFpZ77pJjc5r1bQs5caPWtAu+WWmiSo+8XaUzseapVrfAtiRFbQWnrBxxLLEwF6f6ZG/UgCQCg== + dependencies: + comment-parser "1.4.0" + esquery "^1.5.0" + jsdoc-type-pratt-parser "~4.0.0" + "@es-joy/jsdoccomment@~0.41.0": version "0.41.0" resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz#4a2f7db42209c0425c71a1476ef1bdb6dcd836f6" @@ -626,7 +1546,22 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== -"@eslint/eslintrc@^2.1.4": +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@eslint/eslintrc@^2.1.2", "@eslint/eslintrc@^2.1.4": version "2.1.4" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== @@ -641,6 +1576,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" + integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== + "@eslint/js@8.57.1": version "8.57.1" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" @@ -835,6 +1775,20 @@ tslib "2.8.1" typescript "5.9.2" +"@grafana/eslint-config@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@grafana/eslint-config/-/eslint-config-7.0.0.tgz#9f8474a7d1c63e0510d7076ecbb644850693cb0b" + integrity sha512-LSN6RYntCx9Z7qo5Wm9tjtBfK1vPzvMxQWHuhS0qh9MSMrlC8bZ7FPHFgg9N65q7TYA2SaH2Onz3BLInZFYtDw== + dependencies: + "@typescript-eslint/eslint-plugin" "6.18.1" + "@typescript-eslint/parser" "6.18.1" + eslint "8.52.0" + eslint-config-prettier "8.8.0" + eslint-plugin-jsdoc "46.8.2" + eslint-plugin-react "7.33.2" + eslint-plugin-react-hooks "4.6.0" + typescript "5.2.2" + "@grafana/eslint-config@^8.0.0": version "8.2.0" resolved "https://registry.yarnpkg.com/@grafana/eslint-config/-/eslint-config-8.2.0.tgz#3334f4c763597297223f3ae8a258434a62860111" @@ -909,6 +1863,11 @@ dependencies: tslib "2.8.1" +"@grafana/tsconfig@^1.2.0-rc1": + version "1.2.0-rc1" + resolved "https://registry.yarnpkg.com/@grafana/tsconfig/-/tsconfig-1.2.0-rc1.tgz#10973c978ec95b0ea637511254b5f478bce04de7" + integrity sha512-+SgQeBQ1pT6D/E3/dEdADqTrlgdIGuexUZ8EU+8KxQFKUeFeU7/3z/ayI2q/wpJ/Kr6WxBBNlrST6aOKia19Ag== + "@grafana/tsconfig@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@grafana/tsconfig/-/tsconfig-2.0.1.tgz#231d46e996e53cd04367da850c03f1ef1170484c" @@ -1007,6 +1966,15 @@ dependencies: "@standard-schema/utils" "^0.3.0" +"@humanwhocodes/config-array@^0.11.13": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + "@humanwhocodes/config-array@^0.13.0": version "0.13.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" @@ -1016,12 +1984,26 @@ debug "^4.3.1" minimatch "^3.0.5" +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.3": +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@humanwhocodes/object-schema@^2.0.2", "@humanwhocodes/object-schema@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== @@ -1136,11 +2118,6 @@ dependencies: "@jest/types" "30.2.0" -"@jest/diff-sequences@30.0.1": - version "30.0.1" - resolved "https://registry.yarnpkg.com/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz#0ededeae4d071f5c8ffe3678d15f3a1be09156be" - integrity sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw== - "@jest/environment@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" @@ -1151,13 +2128,6 @@ "@types/node" "*" jest-mock "^29.7.0" -"@jest/expect-utils@30.2.0": - version "30.2.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.2.0.tgz#4f95413d4748454fdb17404bf1141827d15e6011" - integrity sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA== - dependencies: - "@jest/get-type" "30.1.0" - "@jest/expect-utils@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" @@ -1185,11 +2155,6 @@ jest-mock "^29.7.0" jest-util "^29.7.0" -"@jest/get-type@30.1.0": - version "30.1.0" - resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.1.0.tgz#4fcb4dc2ebcf0811be1c04fd1cb79c2dba431cbc" - integrity sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA== - "@jest/globals@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" @@ -1382,6 +2347,15 @@ resolved "https://registry.yarnpkg.com/@leeoniya/ufuzzy/-/ufuzzy-1.0.19.tgz#1d64b6cad17491756b6d7dc6568e7b2376958777" integrity sha512-0pikDeYt0IHEUPza5RTCDXc/17S1pTrYnReEMp8Aa6k1ovzw5QdZLwicW8TjljwEZRb6oYag0xmALohrcq/yOQ== +"@microlink/react-json-view@^1.24.0": + version "1.31.25" + resolved "https://registry.yarnpkg.com/@microlink/react-json-view/-/react-json-view-1.31.25.tgz#986d2e939af96cd50a496d601fb2e6701f525835" + integrity sha512-eVRAzd6GpIWhUwZkk1BHVtyS3Sgcw9eVJYvV/RGxahmV10TD3Z50cZNg4EQOzlEWDw+FeitTtr/Aj1yp7fRYXA== + dependencies: + react-base16-styling "~0.10.0" + react-lifecycles-compat "~3.0.4" + react-textarea-autosize "~8.5.9" + "@monaco-editor/loader@^1.5.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.7.0.tgz#967aaa4601b19e913627688dfe8159d57549e793" @@ -1527,6 +2501,11 @@ resolved "https://registry.yarnpkg.com/@openfeature/core/-/core-1.9.1.tgz#9925a04ed0745e92dd7b3793b35cff1ed89d54c1" integrity sha512-YySPtH4s/rKKnHRU0xyFGrqMU8XA+OIPNWDrlEFxE6DCVWCIrxE5YpiB94YD2jMFn6SSdA0cwQ8vLkCkl8lm8A== +"@openfeature/core@^1.9.2": + version "1.12.0" + resolved "https://registry.yarnpkg.com/@openfeature/core/-/core-1.12.0.tgz#c9c2be428f9ceb1e8aff4e33709efe6005ea99b3" + integrity sha512-7PCPzyd1OC19begz30+CRknFB0ChtyaZUhk7YWrk+Bov1fpVw0HYkTXtoxxsvPfDZB9P9WsT7uixN+Z8f9+bcA== + "@openfeature/ofrep-core@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@openfeature/ofrep-core/-/ofrep-core-2.0.0.tgz#e4d2931e2e4e96d4bd8f43144bb77087bc1b3492" @@ -1544,6 +2523,11 @@ resolved "https://registry.yarnpkg.com/@openfeature/react-sdk/-/react-sdk-1.2.1.tgz#76691248eaee4e8660282852571591e47e5c1313" integrity sha512-W4vRe76HVB/PkCJQGycllIcHCT4q3C++8wFXxL3XZC3VWm7NEnFAzmboXfsMg/6N9KNWh0KRJYQAj0XTWAiyww== +"@openfeature/web-sdk@^1.4.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@openfeature/web-sdk/-/web-sdk-1.10.0.tgz#fa21c61c46f4fdd9df95839e32f76a6604cbb4dc" + integrity sha512-qf+JmJSnaslhegNwoDDLn2Cf72P6cIobuAQPUb61MSkzJOZuVLU6f9pv/90FlLcK6UDtp6od//xZHW712rBrmg== + "@opentelemetry/api-logs@0.202.0": version "0.202.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz#78ddb3b4a30232fd0916b99f27777b1936355d03" @@ -1652,7 +2636,7 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@popperjs/core@2.11.8", "@popperjs/core@^2.11.8": +"@popperjs/core@2.11.8", "@popperjs/core@^2.11.8", "@popperjs/core@^2.9.0": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== @@ -1710,6 +2694,13 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@rc-component/async-validator@^5.0.3": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@rc-component/async-validator/-/async-validator-5.1.2.tgz#59458079b6957d62baa488ee9e053d6e915843f5" + integrity sha512-WYbrZSjzznU1ekD0qFq2qRxt309VoS61MTG5npnFQlKYcoy9IzU8T+ZCIhq5bGAXRbXysABFWTspicMfmWFwow== + dependencies: + "@babel/runtime" "^7.24.4" + "@rc-component/cascader@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@rc-component/cascader/-/cascader-1.9.0.tgz#a9b342d4b545d4f8658d1b00dcc63e4871d9c740" @@ -1720,6 +2711,24 @@ "@rc-component/util" "^1.4.0" clsx "^2.1.1" +"@rc-component/color-picker@~2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@rc-component/color-picker/-/color-picker-2.0.1.tgz#6b9b96152466a9d4475cbe72b40b594bfda164be" + integrity sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q== + dependencies: + "@ant-design/fast-color" "^2.0.6" + "@babel/runtime" "^7.23.6" + classnames "^2.2.6" + rc-util "^5.38.1" + +"@rc-component/context@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@rc-component/context/-/context-1.4.0.tgz#dc6fb021d6773546af8f016ae4ce9aea088395e8" + integrity sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w== + dependencies: + "@babel/runtime" "^7.10.1" + rc-util "^5.27.0" + "@rc-component/drawer@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@rc-component/drawer/-/drawer-1.3.0.tgz#629e789f6199bbc2e2de467bc0dde59ed0817da2" @@ -1730,6 +2739,13 @@ "@rc-component/util" "^1.2.1" clsx "^2.1.1" +"@rc-component/mini-decimal@^1.0.1": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@rc-component/mini-decimal/-/mini-decimal-1.1.4.tgz#36bccedbffb54662ba314a26f63910414f48bc44" + integrity sha512-xiuXcaCwyOWpD8a8scdExFl+bntNphAW8XeenL1ig2en0AAZY0Pcp4pC0dI22qJ+NvxKn9RoNIoRdqYU3BLH4w== + dependencies: + "@babel/runtime" "^7.18.0" + "@rc-component/motion@^1.0.0", "@rc-component/motion@^1.1.4": version "1.3.2" resolved "https://registry.yarnpkg.com/@rc-component/motion/-/motion-1.3.2.tgz#bd96e0fd16ee9d98c1d9be14198f003e367d8feb" @@ -1738,6 +2754,15 @@ "@rc-component/util" "^1.2.0" clsx "^2.1.1" +"@rc-component/mutate-observer@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz#ee53cc88b78aade3cd0653609215a44779386fd8" + integrity sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw== + dependencies: + "@babel/runtime" "^7.18.0" + classnames "^2.3.2" + rc-util "^5.24.4" + "@rc-component/overflow@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@rc-component/overflow/-/overflow-1.0.0.tgz#ade1cc336c66b45eb1631fdfad59ef84c8f90a89" @@ -1759,6 +2784,15 @@ clsx "^2.1.1" rc-overflow "^1.3.2" +"@rc-component/portal@^1.0.0-8", "@rc-component/portal@^1.0.0-9", "@rc-component/portal@^1.0.2", "@rc-component/portal@^1.1.0", "@rc-component/portal@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@rc-component/portal/-/portal-1.1.2.tgz#55db1e51d784e034442e9700536faaa6ab63fc71" + integrity sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg== + dependencies: + "@babel/runtime" "^7.18.0" + classnames "^2.3.2" + rc-util "^5.24.4" + "@rc-component/portal@^2.0.0", "@rc-component/portal@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@rc-component/portal/-/portal-2.2.0.tgz#ec4c6c3de2cd09fa3ce545f2439a7eb84852a7b9" @@ -1767,6 +2801,13 @@ "@rc-component/util" "^1.2.1" clsx "^2.1.1" +"@rc-component/qrcode@~1.1.0": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@rc-component/qrcode/-/qrcode-1.1.3.tgz#5bc69928fda6621b9a4baca336ba33b9e01c7ea6" + integrity sha512-aGv6alnn4HbDEsURzKP+jv13rbi1VxmAYfBNZr5GKF1iohMNWy5tAVoJ1E3cOvzMB1kbUPvCXchM6zSFlRGPhA== + dependencies: + "@babel/runtime" "^7.24.7" + "@rc-component/resize-observer@^1.0.0", "@rc-component/resize-observer@^1.0.1", "@rc-component/resize-observer@^1.1.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@rc-component/resize-observer/-/resize-observer-1.1.2.tgz#5897e65d7fed5c6e768dcfd8bdec181a3309a98f" @@ -1802,6 +2843,17 @@ "@rc-component/util" "^1.3.0" clsx "^2.1.1" +"@rc-component/tour@~1.15.1": + version "1.15.1" + resolved "https://registry.yarnpkg.com/@rc-component/tour/-/tour-1.15.1.tgz#9b79808254185fc19e964172d99e25e8c6800ded" + integrity sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ== + dependencies: + "@babel/runtime" "^7.18.0" + "@rc-component/portal" "^1.0.0-9" + "@rc-component/trigger" "^2.0.0" + classnames "^2.3.2" + rc-util "^5.24.4" + "@rc-component/tree@~1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rc-component/tree/-/tree-1.1.0.tgz#68cca843cd3a9311f729f02f9f75f78a65c8ee48" @@ -1812,6 +2864,18 @@ "@rc-component/virtual-list" "^1.0.1" clsx "^2.1.1" +"@rc-component/trigger@^2.0.0", "@rc-component/trigger@^2.1.1", "@rc-component/trigger@^2.3.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-2.3.1.tgz#83fc0c4165a58fdc66bd9171082d08acf31be6bb" + integrity sha512-ORENF39PeXTzM+gQEshuk460Z8N4+6DkjpxlpE7Q3gYy1iBpLrx0FOJz3h62ryrJZ/3zCAUIkT1Pb/8hHWpb3A== + dependencies: + "@babel/runtime" "^7.23.2" + "@rc-component/portal" "^1.1.0" + classnames "^2.3.2" + rc-motion "^2.0.0" + rc-resize-observer "^1.3.1" + rc-util "^5.44.0" + "@rc-component/trigger@^3.0.0", "@rc-component/trigger@^3.6.15", "@rc-component/trigger@^3.7.1": version "3.9.0" resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-3.9.0.tgz#d4d2df167e9aced1bf17672d9104a3297663f766" @@ -2252,6 +3316,11 @@ resolved "https://registry.yarnpkg.com/@rooks/use-mutation-observer/-/use-mutation-observer-4.11.2.tgz#a0466c4338e0a4487ea19253c86bcd427c29f4af" integrity sha512-vpsdrZdr6TkB1zZJcHx+fR1YC/pHs2BaqcuYiEGjBVbwY5xcC49+h0hAUtQKHth3oJqXfIX/Ng8S7s5HFHdM/A== +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -2454,7 +3523,7 @@ dependencies: tslib "^2.8.0" -"@swc/jest@^0.2.26": +"@swc/jest@^0.2.26", "@swc/jest@^0.2.36": version "0.2.39" resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.39.tgz#482bee0adb0726fab1487a4f902a278ec563a6b7" integrity sha512-eyokjOwYd0Q8RnMHri+8/FS1HIrIUKK/sRrFp8c1dThUOfNeCWbLmBP1P5VsKdvmkd25JaH+OKYwEYiAYg9YAA== @@ -2567,6 +3636,20 @@ lodash "^4.17.15" redent "^3.0.0" +"@testing-library/jest-dom@6.4.6": + version "6.4.6" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.6.tgz#ec1df8108651bed5475534955565bed88c6732ce" + integrity sha512-8qpnGVincVDLEcQXWaHOf6zmlbwTKc6Us6PPu4CRnPXCzo2OGBS5cwgMMOWdxDpEz1mkbvXHpEy99M5Yvt682w== + dependencies: + "@adobe/css-tools" "^4.4.0" + "@babel/runtime" "^7.9.2" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.6.3" + lodash "^4.17.21" + redent "^3.0.0" + "@testing-library/jest-dom@^6.4.8": version "6.9.1" resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz#7613a04e146dd2976d24ddf019730d57a89d56c2" @@ -2579,6 +3662,14 @@ picocolors "^1.1.1" redent "^3.0.0" +"@testing-library/react-hooks@^3.2.1": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-3.7.0.tgz#6d75c5255ef49bce39b6465bf6b49e2dac84919e" + integrity sha512-TwfbY6BWtWIHitjT05sbllyLIProcysC0dF0q1bbDa7OHLC6A6rJOYJwZ13hzfz3O4RtOuInmprBozJRyyo7/g== + dependencies: + "@babel/runtime" "^7.12.5" + "@types/testing-library__react-hooks" "^3.4.0" + "@testing-library/react@14.0.0": version "14.0.0" resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-14.0.0.tgz#59030392a6792450b9ab8e67aea5f3cc18d6347c" @@ -2597,6 +3688,20 @@ "@testing-library/dom" "^10.0.0" "@types/react-dom" "^18.0.0" +"@testing-library/user-event@^12.1.3": + version "12.8.3" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-12.8.3.tgz#1aa3ed4b9f79340a1e1836bc7f57c501e838704a" + integrity sha512-IR0iWbFkgd56Bu5ZI/ej8yQwrkCv8Qydx6RzwbKz9faXazR/+5tvYKsZQgyXJiwgpcva127YO6JcWy7YlCfofQ== + dependencies: + "@babel/runtime" "^7.12.5" + +"@tippyjs/react@^4.2.6": + version "4.2.6" + resolved "https://registry.yarnpkg.com/@tippyjs/react/-/react-4.2.6.tgz#971677a599bf663f20bb1c60a62b9555b749cc71" + integrity sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw== + dependencies: + tippy.js "^6.3.1" + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -2660,17 +3765,215 @@ dependencies: "@babel/types" "^7.28.2" +"@types/d3-array@*": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.2.tgz#e02151464d02d4a1b44646d0fcdb93faf88fde8c" + integrity sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw== + +"@types/d3-axis@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.6.tgz#e760e5765b8188b1defa32bc8bb6062f81e4c795" + integrity sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-brush@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.6.tgz#c2f4362b045d472e1b186cdbec329ba52bdaee6c" + integrity sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-chord@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.6.tgz#1706ca40cf7ea59a0add8f4456efff8f8775793d" + integrity sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg== + "@types/d3-color@*": version "3.1.3" resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== -"@types/d3-interpolate@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" - integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== +"@types/d3-contour@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.6.tgz#9ada3fa9c4d00e3a5093fed0356c7ab929604231" + integrity sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg== + dependencies: + "@types/d3-array" "*" + "@types/geojson" "*" + +"@types/d3-delaunay@*": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz#185c1a80cc807fdda2a3fe960f7c11c4a27952e1" + integrity sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw== + +"@types/d3-dispatch@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz#ef004d8a128046cfce434d17182f834e44ef95b2" + integrity sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA== + +"@types/d3-drag@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.7.tgz#b13aba8b2442b4068c9a9e6d1d82f8bcea77fc02" + integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-dsv@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.7.tgz#0a351f996dc99b37f4fa58b492c2d1c04e3dac17" + integrity sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g== + +"@types/d3-ease@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b" + integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== + +"@types/d3-fetch@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.7.tgz#c04a2b4f23181aa376f30af0283dbc7b3b569980" + integrity sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA== + dependencies: + "@types/d3-dsv" "*" + +"@types/d3-force@*": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.10.tgz#6dc8fc6e1f35704f3b057090beeeb7ac674bff1a" + integrity sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw== + +"@types/d3-format@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-3.0.4.tgz#b1e4465644ddb3fdf3a263febb240a6cd616de90" + integrity sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g== + +"@types/d3-geo@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.1.0.tgz#b9e56a079449174f0a2c8684a9a4df3f60522440" + integrity sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ== + dependencies: + "@types/geojson" "*" + +"@types/d3-hierarchy@*": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz#6023fb3b2d463229f2d680f9ac4b47466f71f17b" + integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg== + +"@types/d3-interpolate@*", "@types/d3-interpolate@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-path@*": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.1.tgz#f632b380c3aca1dba8e34aa049bcd6a4af23df8a" + integrity sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg== + +"@types/d3-polygon@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-3.0.2.tgz#dfae54a6d35d19e76ac9565bcb32a8e54693189c" + integrity sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA== + +"@types/d3-quadtree@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz#d4740b0fe35b1c58b66e1488f4e7ed02952f570f" + integrity sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg== + +"@types/d3-random@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-3.0.4.tgz#6bd3683b8332fc0f01e7059b7636bc5c7ede7337" + integrity sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA== + +"@types/d3-scale-chromatic@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#dc6d4f9a98376f18ea50bad6c39537f1b5463c39" + integrity sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ== + +"@types/d3-scale@*": + version "4.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.9.tgz#57a2f707242e6fe1de81ad7bfcccaaf606179afb" + integrity sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw== + dependencies: + "@types/d3-time" "*" + +"@types/d3-selection@*": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.11.tgz#bd7a45fc0a8c3167a631675e61bc2ca2b058d4a3" + integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w== + +"@types/d3-shape@*": + version "3.1.8" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.8.tgz#d1516cc508753be06852cd06758e3bb54a22b0e3" + integrity sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w== + dependencies: + "@types/d3-path" "*" + +"@types/d3-time-format@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.3.tgz#d6bc1e6b6a7db69cccfbbdd4c34b70632d9e9db2" + integrity sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg== + +"@types/d3-time@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f" + integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g== + +"@types/d3-timer@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70" + integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== + +"@types/d3-transition@*": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.9.tgz#1136bc57e9ddb3c390dccc9b5ff3b7d2b8d94706" + integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-zoom@*": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b" + integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw== + dependencies: + "@types/d3-interpolate" "*" + "@types/d3-selection" "*" + +"@types/d3@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@types/d3/-/d3-7.4.3.tgz#d4550a85d08f4978faf0a4c36b848c61eaac07e2" + integrity sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww== dependencies: + "@types/d3-array" "*" + "@types/d3-axis" "*" + "@types/d3-brush" "*" + "@types/d3-chord" "*" "@types/d3-color" "*" + "@types/d3-contour" "*" + "@types/d3-delaunay" "*" + "@types/d3-dispatch" "*" + "@types/d3-drag" "*" + "@types/d3-dsv" "*" + "@types/d3-ease" "*" + "@types/d3-fetch" "*" + "@types/d3-force" "*" + "@types/d3-format" "*" + "@types/d3-geo" "*" + "@types/d3-hierarchy" "*" + "@types/d3-interpolate" "*" + "@types/d3-path" "*" + "@types/d3-polygon" "*" + "@types/d3-quadtree" "*" + "@types/d3-random" "*" + "@types/d3-scale" "*" + "@types/d3-scale-chromatic" "*" + "@types/d3-selection" "*" + "@types/d3-shape" "*" + "@types/d3-time" "*" + "@types/d3-time-format" "*" + "@types/d3-timer" "*" + "@types/d3-transition" "*" + "@types/d3-zoom" "*" "@types/debug@^4.0.0": version "4.1.12" @@ -2715,6 +4018,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== +"@types/geojson@*": + version "7946.0.16" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.16.tgz#8ebe53d69efada7044454e3305c19017d97ced2a" + integrity sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg== + "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -2722,6 +4030,10 @@ dependencies: "@types/node" "*" +"@types/grafana@https://git@github.com/CorpGlory/types-grafana.git": + version "4.6.3" + resolved "https://git@github.com/CorpGlory/types-grafana.git#4beede5fa0e5bdebdb23b09e4e1e214dcc4c267f" + "@types/hast@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" @@ -2729,6 +4041,11 @@ dependencies: "@types/unist" "*" +"@types/history@^4.7.11": + version "4.7.11" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" + integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1", "@types/istanbul-lib-coverage@^2.0.6": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" @@ -2748,15 +4065,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@*": - version "30.0.0" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-30.0.0.tgz#5e85ae568006712e4ad66f25433e9bdac8801f1d" - integrity sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA== - dependencies: - expect "^30.0.0" - pretty-format "^30.0.0" - -"@types/jest@^29.5.0": +"@types/jest@*", "@types/jest@^29.5.0": version "29.5.14" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== @@ -2785,16 +4094,26 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + "@types/lodash@4.17.20": version "4.17.20" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93" integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA== +"@types/lodash@^4.14.194", "@types/lodash@^4.17.0": + version "4.17.24" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.24.tgz#4ae334fc62c0e915ca8ed8e35dcc6d4eeb29215f" + integrity sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ== + "@types/mdast@^4.0.0": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" @@ -2802,6 +4121,11 @@ dependencies: "@types/unist" "*" +"@types/mocha@^8.0.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.3.tgz#bbeb55fbc73f28ea6de601fbfa4613f58d785323" + integrity sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw== + "@types/ms@*": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" @@ -2846,11 +4170,35 @@ resolved "https://registry.yarnpkg.com/@types/rbush/-/rbush-4.0.0.tgz#b327bf54952e9c924ea6702c36904c2ce1d47f35" integrity sha512-+N+2H39P8X+Hy1I5mC6awlTX54k3FhiUmvt7HWzGJZvF+syUAAxP/stwppS8JE84YHqFgRMv6fCy31202CMFxQ== -"@types/react-dom@^18.0.0", "@types/react-dom@^18.3.0": +"@types/react-dom@^18.0.0", "@types/react-dom@^18.2.0", "@types/react-dom@^18.3.0": version "18.3.7" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.7.tgz#b89ddf2cd83b4feafcc4e2ea41afdfb95a0d194f" integrity sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ== +"@types/react-router-dom@^5.1.5": + version "5.3.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" + integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router@*": + version "5.1.20" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" + integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + +"@types/react-scrollbar@^0.5.1": + version "0.5.8" + resolved "https://registry.yarnpkg.com/@types/react-scrollbar/-/react-scrollbar-0.5.8.tgz#76752c5b2de9945b6de05e9cf04e6697dad9879d" + integrity sha512-9IbpqGrj3PMIipiTug96vHPm/zpDLIV5Vyav5FIY0ULklgOvuVrjbdcqi0WhZrGOXMDxggRb7xKxIYlnQoPA6A== + dependencies: + "@types/react" "*" + "@types/react-table@7.7.20": version "7.7.20" resolved "https://registry.yarnpkg.com/@types/react-table/-/react-table-7.7.20.tgz#2f68e70ca7a703ad8011a8da55c38482f0eb4314" @@ -2858,6 +4206,13 @@ dependencies: "@types/react" "*" +"@types/react-test-renderer@*": + version "19.1.0" + resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-19.1.0.tgz#1d0af8f2e1b5931e245b8b5b234d1502b854dc10" + integrity sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ== + dependencies: + "@types/react" "*" + "@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.12": version "4.4.12" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" @@ -2870,14 +4225,7 @@ dependencies: "@types/react" "*" -"@types/react@*": - version "19.2.14" - resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.14.tgz#39604929b5e3957e3a6fa0001dafb17c7af70bad" - integrity sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w== - dependencies: - csstype "^3.2.2" - -"@types/react@^18.2.15", "@types/react@^18.3.2": +"@types/react@*", "@types/react@^18.2.0", "@types/react@^18.2.15", "@types/react@^18.3.2": version "18.3.27" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.27.tgz#74a3b590ea183983dc65a474dc17553ae1415c34" integrity sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w== @@ -2900,7 +4248,7 @@ resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.10.tgz#277a542aff6776d8a9b15f2ac682a663e3e94bbd" integrity sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww== -"@types/stack-utils@^2.0.0", "@types/stack-utils@^2.0.3": +"@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== @@ -2922,6 +4270,13 @@ dependencies: "@types/jest" "*" +"@types/testing-library__react-hooks@^3.4.0": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@types/testing-library__react-hooks/-/testing-library__react-hooks-3.4.1.tgz#b8d7311c6c1f7db3103e94095fe901f8fef6e433" + integrity sha512-G4JdzEcq61fUyV6wVW9ebHWEiLK2iQvaBuCHHn9eMSbZzVh4Z4wHnUGIvQOYCCYeu5DnUtFyNYuAAgbSaO/43Q== + dependencies: + "@types/react-test-renderer" "*" + "@types/tough-cookie@*": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" @@ -2959,6 +4314,37 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz#0df881a47da1c1a9774f39495f5f7052f86b72e0" + integrity sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.18.1" + "@typescript-eslint/type-utils" "6.18.1" + "@typescript-eslint/utils" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/eslint-plugin@^4.28.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== + dependencies: + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/eslint-plugin@^6.18.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" @@ -2991,6 +4377,39 @@ natural-compare "^1.4.0" ts-api-utils "^1.3.0" +"@typescript-eslint/experimental-utils@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/experimental-utils@^2.5.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" + integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.34.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.18.1.tgz#3c3987e186b38c77b30b6bfa5edf7c98ae2ec9d3" + integrity sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA== + dependencies: + "@typescript-eslint/scope-manager" "6.18.1" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/typescript-estree" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" + debug "^4.3.4" + "@typescript-eslint/parser@^6.18.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" @@ -3031,6 +4450,22 @@ "@typescript-eslint/types" "^8.54.0" debug "^4.4.3" +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/scope-manager@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz#28c31c60f6e5827996aa3560a538693cb4bd3848" + integrity sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw== + dependencies: + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" + "@typescript-eslint/scope-manager@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" @@ -3078,6 +4513,16 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz#cf2f2822af3887d25dd325b6bea6c3f60a83a0b4" integrity sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA== +"@typescript-eslint/type-utils@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz#115cf535f8b39db8301677199ce51151e2daee96" + integrity sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q== + dependencies: + "@typescript-eslint/typescript-estree" "6.18.1" + "@typescript-eslint/utils" "6.18.1" + debug "^4.3.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/type-utils@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" @@ -3098,6 +4543,16 @@ debug "^4.3.4" ts-api-utils "^1.3.0" +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + +"@typescript-eslint/types@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.18.1.tgz#91617d8080bcd99ac355d9157079970d1d49fefc" + integrity sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw== + "@typescript-eslint/types@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" @@ -3118,6 +4573,46 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.54.0.tgz#c12d41f67a2e15a8a96fbc5f2d07b17331130889" integrity sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA== +"@typescript-eslint/typescript-estree@2.34.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" + integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/typescript-estree@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz#a12b6440175b4cbc9d09ab3c4966c6b245215ab4" + integrity sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA== + dependencies: + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/typescript-estree@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" @@ -3176,6 +4671,19 @@ tinyglobby "^0.2.15" ts-api-utils "^2.4.0" +"@typescript-eslint/utils@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.18.1.tgz#3451cfe2e56babb6ac657e10b6703393d4b82955" + integrity sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.18.1" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/typescript-estree" "6.18.1" + semver "^7.5.4" + "@typescript-eslint/utils@6.21.0", "@typescript-eslint/utils@^6.0.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" @@ -3219,6 +4727,22 @@ "@typescript-eslint/types" "8.53.1" "@typescript-eslint/typescript-estree" "8.53.1" +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + +"@typescript-eslint/visitor-keys@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz#704d789bda2565a15475e7d22f145b8fe77443f4" + integrity sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA== + dependencies: + "@typescript-eslint/types" "6.18.1" + eslint-visitor-keys "^3.4.1" + "@typescript-eslint/visitor-keys@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" @@ -3502,7 +5026,7 @@ acorn-import-phases@^1.0.3: resolved "https://registry.yarnpkg.com/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz#16eb850ba99a056cb7cbfe872ffb8972e18c8bd7" integrity sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ== -acorn-jsx@^5.3.2: +acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -3514,11 +5038,23 @@ acorn-walk@^8.0.2, acorn-walk@^8.1.1: dependencies: acorn "^8.11.0" +acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + acorn@^8.1.0, acorn@^8.11.0, acorn@^8.15.0, acorn@^8.4.1, acorn@^8.8.1, acorn@^8.9.0: version "8.15.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== +add-dom-event-listener@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" + integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw== + dependencies: + object-assign "4.x" + add-px-to-style@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a" @@ -3555,6 +5091,16 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" +ajv@^6.10.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.15.0.tgz#07e982c74626167aa7a2495c53817892d7139492" + integrity sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@^6.12.4, ajv@^6.12.5: version "6.14.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.14.0.tgz#fd067713e228210636ebb08c60bd3765d6dbe73a" @@ -3575,6 +5121,21 @@ ajv@^8.0.0, ajv@^8.9.0: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" +ajv@^8.0.1: + version "8.20.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.20.0.tgz#304b3636add88ba7d936760dd50ece006dea95f9" + integrity sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -3592,6 +5153,13 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -3599,7 +5167,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^5.0.0, ansi-styles@^5.2.0: +ansi-styles@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== @@ -3609,6 +5177,61 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== +antd@^5.19.2: + version "5.29.3" + resolved "https://registry.yarnpkg.com/antd/-/antd-5.29.3.tgz#404eda9f9716b2ff9b06251dfecb7028d7c4de40" + integrity sha512-3DdbGCa9tWAJGcCJ6rzR8EJFsv2CtyEbkVabZE14pfgUHfCicWCj0/QzQVLDYg8CPfQk9BH7fHCoTXHTy7MP/A== + dependencies: + "@ant-design/colors" "^7.2.1" + "@ant-design/cssinjs" "^1.23.0" + "@ant-design/cssinjs-utils" "^1.1.3" + "@ant-design/fast-color" "^2.0.6" + "@ant-design/icons" "^5.6.1" + "@ant-design/react-slick" "~1.1.2" + "@babel/runtime" "^7.26.0" + "@rc-component/color-picker" "~2.0.1" + "@rc-component/mutate-observer" "^1.1.0" + "@rc-component/qrcode" "~1.1.0" + "@rc-component/tour" "~1.15.1" + "@rc-component/trigger" "^2.3.0" + classnames "^2.5.1" + copy-to-clipboard "^3.3.3" + dayjs "^1.11.11" + rc-cascader "~3.34.0" + rc-checkbox "~3.5.0" + rc-collapse "~3.9.0" + rc-dialog "~9.6.0" + rc-drawer "~7.3.0" + rc-dropdown "~4.2.1" + rc-field-form "~2.7.1" + rc-image "~7.12.0" + rc-input "~1.8.0" + rc-input-number "~9.5.0" + rc-mentions "~2.20.0" + rc-menu "~9.16.1" + rc-motion "^2.9.5" + rc-notification "~5.6.4" + rc-pagination "~5.1.0" + rc-picker "~4.11.3" + rc-progress "~4.0.0" + rc-rate "~2.13.1" + rc-resize-observer "^1.4.3" + rc-segmented "~2.7.0" + rc-select "~14.16.8" + rc-slider "~11.1.9" + rc-steps "~6.0.1" + rc-switch "~4.1.0" + rc-table "~7.54.0" + rc-tabs "~15.7.0" + rc-textarea "~1.10.2" + rc-tooltip "~6.4.0" + rc-tree "~5.13.1" + rc-tree-select "~5.27.0" + rc-upload "~4.11.0" + rc-util "^5.44.4" + scroll-into-view-if-needed "^3.1.0" + throttle-debounce "^5.0.2" + anymatch@^3.0.3, anymatch@^3.1.1, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -3653,7 +5276,7 @@ aria-query@5.3.0: dependencies: dequal "^2.0.3" -aria-query@^5.0.0: +aria-query@^5.0.0, aria-query@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== @@ -3666,7 +5289,7 @@ array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1, array-buffer-b call-bound "^1.0.3" is-array-buffer "^3.0.5" -array-includes@^3.1.6, array-includes@^3.1.8: +array-includes@^3.1.6, array-includes@^3.1.8, array-includes@^3.1.9: version "3.1.9" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.9.tgz#1f0ccaa08e90cdbc3eb433210f903ad0f17c3f3a" integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ== @@ -3697,7 +5320,20 @@ array.prototype.findlast@^1.2.5: es-object-atoms "^1.0.0" es-shim-unscopables "^1.0.2" -array.prototype.flat@^1.3.1: +array.prototype.findlastindex@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz#cfa1065c81dcb64e34557c9b81d012f6a421c564" + integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-shim-unscopables "^1.1.0" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== @@ -3707,7 +5343,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.23.5" es-shim-unscopables "^1.0.2" -array.prototype.flatmap@^1.3.3: +array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2, array.prototype.flatmap@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== @@ -3717,7 +5353,7 @@ array.prototype.flatmap@^1.3.3: es-abstract "^1.23.5" es-shim-unscopables "^1.0.2" -array.prototype.tosorted@^1.1.4: +array.prototype.tosorted@^1.1.1, array.prototype.tosorted@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== @@ -3746,11 +5382,26 @@ assertion-error@^2.0.1: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + async-function@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== +async-validator@~1.11.3: + version "1.11.5" + resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-1.11.5.tgz#9d43cf49ef6bb76be5442388d19fb9a6e47597ea" + integrity sha512-XNtCsMAeAH1pdLMEg1z8/Bb3a8cdCbui9QbJATRFHHHW5kT6+NPI3zSVQUXgikTFITzsg+kYY5NTWhM2Orwt9w== + async@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" @@ -3773,6 +5424,11 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +axe-core@^4.10.0: + version "4.12.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.12.1.tgz#69fe2bf6dfc0b24973af91b1d8e945f79e1b7c44" + integrity sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA== + axios-case-converter@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/axios-case-converter/-/axios-case-converter-1.1.1.tgz#7aad2194c30265513b50ee0433cbd15380d89a8a" @@ -3792,6 +5448,11 @@ axios@^1.13.5: form-data "^4.0.5" proxy-from-env "^1.1.0" +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -3835,6 +5496,30 @@ babel-plugin-macros@^3.1.0: cosmiconfig "^7.0.0" resolve "^1.19.0" +babel-plugin-polyfill-corejs2@^0.4.15: + version "0.4.17" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz#198f970f1c99a856b466d1187e88ce30bd199d91" + integrity sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-define-polyfill-provider" "^0.6.8" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.14.0: + version "0.14.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz#6ac08d2f312affb70c4c69c0fbba4cb417ee5587" + integrity sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.8" + core-js-compat "^3.48.0" + +babel-plugin-polyfill-regenerator@^0.6.6: + version "0.6.8" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz#8a6bfd5dd54239362b3d06ce47ac52b2d95d7721" + integrity sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.8" + babel-preset-current-node-syntax@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" @@ -3864,6 +5549,14 @@ babel-preset-jest@^29.6.3: babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" +babel-runtime@6.x: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + bail@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" @@ -3982,6 +5675,16 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.7, call-bind@^1.0.8: get-intrinsic "^1.2.4" set-function-length "^1.2.2" +call-bind@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.9.tgz#39a644700c80bc7d0ca9102fc6d1d43b2fd7eee7" + integrity sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + get-intrinsic "^1.3.0" + set-function-length "^1.2.2" + call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" @@ -4058,18 +5761,27 @@ chai@^5.1.2: loupe "^3.1.0" pathval "^2.0.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, 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@^4.0.0, chalk@^4.1.0, 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== +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" @@ -4099,12 +5811,22 @@ character-reference-invalid@^2.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== +chart.js@^3.7.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.9.1.tgz#3abf2c775169c4c71217a107163ac708515924b8" + integrity sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w== + +chartjs-plugin-datalabels@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz#369578e131d743c2e34b5fbe2d3f9335f6639b8f" + integrity sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw== + check-error@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -4129,17 +5851,12 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -ci-info@^4.2.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.3.1.tgz#355ad571920810b5623e11d40232f443f16f1daa" - integrity sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA== - cjs-module-lexer@^1.0.0: version "1.4.3" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== -classnames@2.5.1, classnames@^2.2.1: +classnames@2.5.1, classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== @@ -4182,6 +5899,13 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -4189,11 +5913,32 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + colord@^2.9.1: version "2.9.3" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" @@ -4231,6 +5976,11 @@ commander@^2.20.0, commander@^2.20.3: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +comment-parser@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.0.tgz#0f8c560f59698193854f12884c20c0e39a26d32c" + integrity sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw== + comment-parser@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" @@ -4241,7 +5991,7 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== -compute-scroll-into-view@^3.1.0: +compute-scroll-into-view@^3.0.2, compute-scroll-into-view@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz#02c3386ec531fb6a9881967388e53e8564f3e9aa" integrity sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw== @@ -4258,6 +6008,23 @@ concat-with-sourcemaps@^1.1.0: dependencies: source-map "^0.6.1" +concurrently@^9.1.0: + version "9.2.4" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.2.4.tgz#4cd9bba735ade2ccb287f000f8706513d2f581f8" + integrity sha512-TZ0CEhyzvFjgtAvHTusDMgj7wNdihCh7LLLrzdUOXIhdlnL2JBBGA9eJxR24rtqgmdjh3OA3hrN1rCHj6HM8qA== + dependencies: + chalk "4.1.2" + rxjs "7.8.2" + shell-quote "1.9.0" + supports-color "8.1.1" + tree-kill "1.2.2" + yargs "17.7.2" + +confusing-browser-globals@^1.0.10: + version "1.0.11" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" + integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== + continuable-cache@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" @@ -4273,7 +6040,14 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -copy-to-clipboard@^3.3.1: +copy-anything@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-3.0.5.tgz#2d92dce8c498f790fa7ad16b01a1ae5a45b020a0" + integrity sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w== + dependencies: + is-what "^4.1.8" + +copy-to-clipboard@^3.3.1, copy-to-clipboard@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== @@ -4292,6 +6066,18 @@ copy-webpack-plugin@^11.0.0: schema-utils "^4.0.0" serialize-javascript "^6.0.0" +core-js-compat@^3.48.0: + version "3.49.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.49.0.tgz#06145447d92f4aaf258a0c44f24b47afaeaffef6" + integrity sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA== + dependencies: + browserslist "^4.28.1" + +core-js@^2.4.0: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" @@ -4326,6 +6112,14 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" +create-react-class@^15.5.3: + version "15.7.0" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e" + integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -4412,6 +6206,11 @@ cssfilter@0.0.10: resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" integrity sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw== +cssfontparser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/cssfontparser/-/cssfontparser-1.2.1.tgz#f4022fc8f9700c68029d542084afbaf425a3f3e3" + integrity sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg== + cssnano-preset-default@^5.2.14: version "5.2.14" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8" @@ -4498,7 +6297,7 @@ csstype@^3.0.2, csstype@^3.1.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -csstype@^3.2.2, csstype@^3.2.3: +csstype@^3.1.3, csstype@^3.2.2, csstype@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== @@ -4711,7 +6510,7 @@ d3-zoom@3: d3-selection "2 - 3" d3-transition "2 - 3" -d3@7.9.0: +d3@7.9.0, d3@^7.9.0: version "7.9.0" resolved "https://registry.yarnpkg.com/d3/-/d3-7.9.0.tgz#579e7acb3d749caf8860bd1741ae8d371070cd5d" integrity sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA== @@ -4747,6 +6546,11 @@ d3@7.9.0: d3-transition "3" d3-zoom "3" +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + data-urls@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" @@ -4796,14 +6600,26 @@ date-fns@4.1.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14" integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg== -debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7, debug@^4.4.3: +dayjs@^1.11.11, dayjs@^1.11.4: + version "1.11.21" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.21.tgz#57f87562e62de76f3c704bd2b8d522fc33068eb2" + integrity sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA== + +debug@2: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7, debug@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: ms "^2.1.3" -debug@^3.1.0: +debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -4976,6 +6792,11 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +dom-scroll-into-view@1.x: + version "1.2.1" + resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz#e8f36732dd089b0201a88d7815dc3f88e6d66c7e" + integrity sha512-LwNVg3GJOprWDO+QhLL1Z9MMgWe/KAFLxVWKzjRTxNSPn8/LLDIfmuG71YHznXCqaqTjvHJDYO1MEAgX6XCNbQ== + dom-serializer@^1.0.1: version "1.4.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" @@ -5086,6 +6907,14 @@ enhanced-resolve@^5.17.4: graceful-fs "^4.2.4" tapable "^2.3.0" +enquirer@^2.3.5: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + entities@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -5106,6 +6935,13 @@ envinfo@^7.7.3: resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.21.0.tgz#04a251be79f92548541f37d13c8b6f22940c3bae" integrity sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow== +errno@^0.1.1: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + error-ex@^1.3.1: version "1.3.4" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414" @@ -5127,10 +6963,70 @@ error@^7.0.0: dependencies: string-template "~0.2.1" -es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0, es-abstract@^1.24.1: - version "1.24.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.1.tgz#f0c131ed5ea1bb2411134a8dd94def09c46c7899" - integrity sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw== +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0, es-abstract@^1.24.1: + version "1.24.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.1.tgz#f0c131ed5ea1bb2411134a8dd94def09c46c7899" + integrity sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.3.0" + get-proto "^1.0.1" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-negative-zero "^2.0.3" + is-regex "^1.2.1" + is-set "^2.0.3" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.1" + math-intrinsics "^1.1.0" + object-inspect "^1.13.4" + object-keys "^1.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.4" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + stop-iteration-iterator "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.19" + +es-abstract@^1.24.2: + version "1.24.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.2.tgz#2dbd38c180735ee983f77585140a2706a963ed9a" + integrity sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg== dependencies: array-buffer-byte-length "^1.0.2" arraybuffer.prototype.slice "^1.0.4" @@ -5212,6 +7108,28 @@ es-get-iterator@^1.1.3: isarray "^2.0.5" stop-iteration-iterator "^1.0.0" +es-iterator-helpers@^1.0.12: + version "1.4.0" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz#2b4635ee3e8db2285378a47a1ea8f8dd34adb653" + integrity sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q== + dependencies: + call-bind "^1.0.9" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.2" + es-errors "^1.3.0" + es-set-tostringtag "^2.1.0" + function-bind "^1.1.2" + get-intrinsic "^1.3.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + iterator.prototype "^1.1.5" + math-intrinsics "^1.1.0" + es-iterator-helpers@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz#d979a9f686e2b0b72f88dbead7229924544720bc" @@ -5261,7 +7179,7 @@ es-set-tostringtag@^2.1.0: has-tostringtag "^1.0.2" hasown "^2.0.2" -es-shim-unscopables@^1.0.2: +es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== @@ -5314,6 +7232,11 @@ escalade@^3.1.1, escalade@^3.2.0: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + escape-string-regexp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" @@ -5340,6 +7263,34 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" +eslint-config-airbnb-base@^14.2.1: + version "14.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" + integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== + dependencies: + confusing-browser-globals "^1.0.10" + object.assign "^4.1.2" + object.entries "^1.1.2" + +eslint-config-airbnb@^18.1.0: + version "18.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz#b7fe2b42f9f8173e825b73c8014b592e449c98d9" + integrity sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg== + dependencies: + eslint-config-airbnb-base "^14.2.1" + object.assign "^4.1.2" + object.entries "^1.1.2" + +eslint-config-prettier@8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== + +eslint-config-prettier@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz#f4a4bd2832e810e8cc7c1411ec85b3e85c0c53f9" + integrity sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg== + eslint-config-prettier@^8.8.0: version "8.10.2" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.2.tgz#0642e53625ebc62c31c24726b0f050df6bd97a2e" @@ -5350,6 +7301,22 @@ eslint-config-prettier@^9.1.0: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz#90deb4fa0259592df774b600dbd1d2249a78ce91" integrity sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ== +eslint-import-resolver-node@^0.3.9: + version "0.3.10" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz#84ce3005abfc300588cf23bbac1aabec1fc6e8c1" + integrity sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ== + dependencies: + debug "^3.2.7" + is-core-module "^2.16.1" + resolve "^2.0.0-next.6" + +eslint-module-utils@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz#611f8e1c6ceb29a93eb949e1cc670b8287764819" + integrity sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig== + dependencies: + debug "^3.2.7" + eslint-plugin-deprecation@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-deprecation/-/eslint-plugin-deprecation-2.0.0.tgz#9804707a4c19f3a53615c6babc0ced3d429d69cf" @@ -5359,7 +7326,54 @@ eslint-plugin-deprecation@^2.0.0: tslib "^2.3.1" tsutils "^3.21.0" -eslint-plugin-jsdoc@^46.8.0: +eslint-plugin-import@^2.20.2: + version "2.32.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz#602b55faa6e4caeaa5e970c198b5c00a37708980" + integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.9" + array.prototype.findlastindex "^1.2.6" + array.prototype.flat "^1.3.3" + array.prototype.flatmap "^1.3.3" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.1" + hasown "^2.0.2" + is-core-module "^2.16.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.1" + semver "^6.3.1" + string.prototype.trimend "^1.0.9" + tsconfig-paths "^3.15.0" + +eslint-plugin-jest@^23.13.2: + version "23.20.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.20.0.tgz#e1d69c75f639e99d836642453c4e75ed22da4099" + integrity sha512-+6BGQt85OREevBDWCvhqj1yYA4+BFK4XnRZSGJionuEYmcglMZYLNNBBemwzbqUAckURaHdJSBcjHPyrtypZOw== + dependencies: + "@typescript-eslint/experimental-utils" "^2.5.0" + +eslint-plugin-jsdoc@46.8.2: + version "46.8.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.2.tgz#3e6b1c93e91e38fe01874d45da121b56393c54a5" + integrity sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ== + dependencies: + "@es-joy/jsdoccomment" "~0.40.1" + are-docs-informative "^0.0.2" + comment-parser "1.4.0" + debug "^4.3.4" + escape-string-regexp "^4.0.0" + esquery "^1.5.0" + is-builtin-module "^3.2.1" + semver "^7.5.4" + spdx-expression-parse "^3.0.1" + +eslint-plugin-jsdoc@^46.8.0, eslint-plugin-jsdoc@^46.9.0: version "46.10.1" resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz#77c871309c4ed93758a3b2fdf384dc6189cf8605" integrity sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag== @@ -5374,7 +7388,47 @@ eslint-plugin-jsdoc@^46.8.0: semver "^7.5.4" spdx-expression-parse "^4.0.0" -eslint-plugin-react-hooks@^4.6.0, eslint-plugin-react-hooks@^4.6.2: +eslint-plugin-jsx-a11y@^6.2.3: + version "6.10.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483" + integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q== + dependencies: + aria-query "^5.3.2" + array-includes "^3.1.8" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "^4.10.0" + axobject-query "^4.1.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + hasown "^2.0.2" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.1" + +eslint-plugin-no-inline-styles@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-no-inline-styles/-/eslint-plugin-no-inline-styles-1.0.5.tgz#c37a7e7a53b46312852d2c44c02cac0df2e700c3" + integrity sha512-nftOfHV/ag0P0vEPQ3p54HVpGCp6k/E+pHdYnRm2wDK8QhClfmMjrCw+POL5RH/SN1AmTifCTh5VzkeubLgMpA== + dependencies: + lodash.get "^4.4.2" + +eslint-plugin-prettier@^3.3.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" + integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-plugin-react-hooks@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + +eslint-plugin-react-hooks@^4.2.0, eslint-plugin-react-hooks@^4.6.0, eslint-plugin-react-hooks@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== @@ -5384,7 +7438,29 @@ eslint-plugin-react-refresh@^0.4.7: resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz#2bcdd109ea9fb4e0b56bb1b5146cf8841b21b626" integrity sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ== -eslint-plugin-react@^7.33.0: +eslint-plugin-react@7.33.2: + version "7.33.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" + integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== + dependencies: + array-includes "^3.1.6" + array.prototype.flatmap "^1.3.1" + array.prototype.tosorted "^1.1.1" + doctrine "^2.1.0" + es-iterator-helpers "^1.0.12" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.6" + object.fromentries "^2.0.6" + object.hasown "^1.1.2" + object.values "^1.1.6" + prop-types "^15.8.1" + resolve "^2.0.0-next.4" + semver "^6.3.1" + string.prototype.matchall "^4.0.8" + +eslint-plugin-react@^7.22.0, eslint-plugin-react@^7.33.0: version "7.37.5" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== @@ -5408,7 +7484,7 @@ eslint-plugin-react@^7.33.0: string.prototype.matchall "^4.0.12" string.prototype.repeat "^1.0.0" -eslint-scope@5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.0.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -5424,6 +7500,30 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" +eslint-utils@^2.0.0, eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" @@ -5434,7 +7534,7 @@ eslint-visitor-keys@^4.2.0, eslint-visitor-keys@^4.2.1: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== -eslint-webpack-plugin@^4.0.1: +eslint-webpack-plugin@^4.0.1, eslint-webpack-plugin@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-4.2.0.tgz#41f54b25379908eb9eca8645bc997c90cfdbd34e" integrity sha512-rsfpFQ01AWQbqtjgPRr2usVRxhWDuG0YDYcG8DJOteD3EFnpeuYuOwk0PQiN7PRBTqS6ElNdtPZPggj8If9WnA== @@ -5445,6 +7545,96 @@ eslint-webpack-plugin@^4.0.1: normalize-path "^3.0.0" schema-utils "^4.2.0" +eslint@8.52.0: + version "8.52.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" + integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "8.52.0" + "@humanwhocodes/config-array" "^0.11.13" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +eslint@^7.21.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + eslint@^8.0.0, eslint@^8.57.0: version "8.57.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" @@ -5498,6 +7688,15 @@ espree@^10.3.0: acorn-jsx "^5.3.2" eslint-visitor-keys "^4.2.1" +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" @@ -5512,7 +7711,7 @@ esprima@^4.0.0, esprima@^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.2, esquery@^1.5.0: +esquery@^1.4.0, esquery@^1.4.2, esquery@^1.5.0: version "1.7.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== @@ -5619,17 +7818,10 @@ expect@^29.0.0, expect@^29.7.0: jest-message-util "^29.7.0" jest-util "^29.7.0" -expect@^30.0.0: - version "30.2.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-30.2.0.tgz#d4013bed267013c14bc1199cec8aa57cee9b5869" - integrity sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw== - dependencies: - "@jest/expect-utils" "30.2.0" - "@jest/get-type" "30.1.0" - jest-matcher-utils "30.2.0" - jest-message-util "30.2.0" - jest-mock "30.2.0" - jest-util "30.2.0" +exponential-backoff@^3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz#51cf92c1c0493c766053f9d3abee4434c244d2f6" + integrity sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA== export-to-csv@^1.4.0: version "1.4.0" @@ -5646,6 +7838,11 @@ 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-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.0: version "3.3.3" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" @@ -5739,6 +7936,13 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" +final-form@^4.20.2: + version "4.20.10" + resolved "https://registry.yarnpkg.com/final-form/-/final-form-4.20.10.tgz#1a484be6e9a91989121c054dcbd6f48bad051ecc" + integrity sha512-TL48Pi1oNHeMOHrKv1bCJUrWZDcD3DIG6AGYVNOnyZPr7Bd/pStN0pL+lfzF5BNoj/FclaoiaLenk4XUIFVYng== + dependencies: + "@babel/runtime" "^7.10.0" + find-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" @@ -5869,6 +8073,11 @@ function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: hasown "^2.0.2" is-callable "^1.2.7" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -6003,7 +8212,7 @@ glob@^10.5.0: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3, glob@^7.1.4: +glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -6026,7 +8235,7 @@ glob@^8.0.3: minimatch "^5.0.1" once "^1.3.0" -globals@^13.19.0: +globals@^13.19.0, globals@^13.6.0, globals@^13.9.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== @@ -6041,7 +8250,7 @@ globalthis@^1.0.4: define-properties "^1.2.1" gopd "^1.0.1" -globby@^11.1.0: +globby@^11.0.3, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -6111,6 +8320,11 @@ has-bigints@^1.0.2: resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -6149,6 +8363,13 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" +hasown@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.4.tgz#8c62d8cb90beb2aad5d0a5b67581ad9854c3f003" + integrity sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A== + dependencies: + function-bind "^1.1.2" + hast-util-from-parse5@^8.0.0: version "8.0.3" resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz#830a35022fff28c3fea3697a98c2f4cc6b835a2e" @@ -6259,7 +8480,12 @@ highlight-words@2.0.0: resolved "https://registry.yarnpkg.com/highlight-words/-/highlight-words-2.0.0.tgz#06853d68f1f7c8e59d6ef2dd072fe2f64fc93936" integrity sha512-If5n+IhSBRXTScE7wl16VPmd+44Vy7kof24EdqhjsZsDuHikpv1OCagVcJFpB4fS4UPUniedlWqrjIO8vWOsIQ== -history@4.10.1: +highlight.js@^11.4.0: + version "11.11.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.11.1.tgz#fca06fa0e5aeecf6c4d437239135fabc15213585" + integrity sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w== + +history@4.10.1, history@^4.10.1: version "4.10.1" resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== @@ -6278,7 +8504,7 @@ history@^5.3.0: dependencies: "@babel/runtime" "^7.7.6" -hoist-non-react-statics@3.3.2, hoist-non-react-statics@^3.3.1: +hoist-non-react-statics@3.3.2, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6397,13 +8623,20 @@ i18next@^25.0.0: dependencies: "@babel/runtime" "^7.28.4" -iconv-lite@0.6, iconv-lite@0.6.3: +iconv-lite@0.6, iconv-lite@0.6.3, 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== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -6421,7 +8654,12 @@ identity-obj-proxy@3.0.0: dependencies: harmony-reflect "^1.4.6" -ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.8, ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -6438,7 +8676,7 @@ import-cwd@^3.0.0: dependencies: import-from "^3.0.0" -import-fresh@^3.2.1, import-fresh@^3.3.0: +import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== @@ -6487,6 +8725,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" +influx@^5.5.2: + version "5.12.0" + resolved "https://registry.yarnpkg.com/influx/-/influx-5.12.0.tgz#14294d5bd77cb2d74a4575ed7c4c9a186444da1e" + integrity sha512-qS3qh7Rt/3/iFUBcDC2wdfxAxgfQKFt9FXKA/PTb7dQD5FIDod9v8LlOxK43Mj71y7umRb9NjkYWw1sk8wfTQQ== + inherits@2: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" @@ -6575,6 +8818,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-arrayish@^0.3.1: + version "0.3.4" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.4.tgz#1ee5553818511915685d33bb13d31bf854e5059d" + integrity sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA== + is-async-function@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" @@ -6627,6 +8875,13 @@ is-core-module@^2.13.0, is-core-module@^2.16.1: dependencies: hasown "^2.0.2" +is-core-module@^2.16.2: + version "2.16.2" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.2.tgz#3e07450a8080ebce3fbf0cac494f4d2ab324e082" + integrity sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA== + dependencies: + hasown "^2.0.3" + is-data-view@^1.0.1, is-data-view@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" @@ -6842,6 +9097,11 @@ is-weakset@^2.0.3: call-bound "^1.0.3" get-intrinsic "^1.2.6" +is-what@^4.1.8: + version "4.1.16" + resolved "https://registry.yarnpkg.com/is-what/-/is-what-4.1.16.tgz#1ad860a19da8b4895ad5495da3182ce2acdd7a6f" + integrity sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A== + is-window@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-window/-/is-window-1.0.2.tgz#2c896ca53db97de45d3c33133a65d8c9f563480d" @@ -6941,6 +9201,14 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jest-canvas-mock@^2.5.2: + version "2.5.8" + resolved "https://registry.yarnpkg.com/jest-canvas-mock/-/jest-canvas-mock-2.5.8.tgz#f9b44e2957dd6be1e2af11f3ce5cccf97bc13993" + integrity sha512-RUZRaFHCnLjg0/UAodCai5PTsa7kQI1rUXE5wsQu9f2315dh2YSN7/i3fObTycs7PO09DLSiGXiJTALYIw2yuw== + dependencies: + cssfontparser "^1.2.1" + moo-color "^1.0.2" + jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -7021,16 +9289,6 @@ jest-config@^29.7.0: slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@30.2.0: - version "30.2.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.2.0.tgz#e3ec3a6ea5c5747f605c9e874f83d756cba36825" - integrity sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A== - dependencies: - "@jest/diff-sequences" "30.0.1" - "@jest/get-type" "30.1.0" - chalk "^4.1.2" - pretty-format "30.2.0" - jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" @@ -7059,7 +9317,7 @@ jest-each@^29.7.0: jest-util "^29.7.0" pretty-format "^29.7.0" -jest-environment-jsdom@^29.5.0: +jest-environment-jsdom@^29.5.0, jest-environment-jsdom@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz#d206fa3551933c3fd519e5dfdb58a0f5139a837f" integrity sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA== @@ -7117,16 +9375,6 @@ jest-leak-detector@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-matcher-utils@30.2.0: - version "30.2.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz#69a0d4c271066559ec8b0d8174829adc3f23a783" - integrity sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg== - dependencies: - "@jest/get-type" "30.1.0" - chalk "^4.1.2" - jest-diff "30.2.0" - pretty-format "30.2.0" - jest-matcher-utils@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" @@ -7137,21 +9385,6 @@ jest-matcher-utils@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-message-util@30.2.0: - version "30.2.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.2.0.tgz#fc97bf90d11f118b31e6131e2b67fc4f39f92152" - integrity sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw== - dependencies: - "@babel/code-frame" "^7.27.1" - "@jest/types" "30.2.0" - "@types/stack-utils" "^2.0.3" - chalk "^4.1.2" - graceful-fs "^4.2.11" - micromatch "^4.0.8" - pretty-format "30.2.0" - slash "^3.0.0" - stack-utils "^2.0.6" - jest-message-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" @@ -7167,15 +9400,6 @@ jest-message-util@^29.7.0: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@30.2.0: - version "30.2.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.2.0.tgz#69f991614eeb4060189459d3584f710845bff45e" - integrity sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw== - dependencies: - "@jest/types" "30.2.0" - "@types/node" "*" - jest-util "30.2.0" - jest-mock@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" @@ -7304,18 +9528,6 @@ jest-snapshot@^29.7.0: pretty-format "^29.7.0" semver "^7.5.3" -jest-util@30.2.0: - version "30.2.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.2.0.tgz#5142adbcad6f4e53c2776c067a4db3c14f913705" - integrity sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA== - dependencies: - "@jest/types" "30.2.0" - "@types/node" "*" - chalk "^4.1.2" - ci-info "^4.2.0" - graceful-fs "^4.2.11" - picomatch "^4.0.2" - jest-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" @@ -7477,7 +9689,7 @@ jsdom@^24.1.1: ws "^8.18.0" xml-name-validator "^5.0.0" -jsesc@^3.0.2: +jsesc@^3.0.2, jsesc@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== @@ -7507,7 +9719,21 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json5@^2.2.3: +json2mq@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" + integrity sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA== + dependencies: + string-convert "^0.2.0" + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -7526,7 +9752,7 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -"jsx-ast-utils@^2.4.1 || ^3.0.0": +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== @@ -7558,11 +9784,44 @@ klona@^2.0.6: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== +language-subtag-registry@^0.3.20: + version "0.3.23" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" + integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== + +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== + dependencies: + language-subtag-registry "^0.3.20" + lerc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lerc/-/lerc-3.0.0.tgz#36f36fbd4ba46f0abf4833799fff2e7d6865f5cb" integrity sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww== +less-loader@^11.1.3: + version "11.1.4" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-11.1.4.tgz#e8a070844efaefbe59b978acaf57b9d3e868cf08" + integrity sha512-6/GrYaB6QcW6Vj+/9ZPgKKs6G10YZai/l/eJ4SLwbzqNTBsAqt5hSLVF47TgsiBxV1P6eAU0GYRH3YRuQU9V3A== + +less@^4.2.0: + version "4.8.1" + resolved "https://registry.yarnpkg.com/less/-/less-4.8.1.tgz#eda5a5c92f21507da6e0f88346a76c37e3403f7b" + integrity sha512-jQ3lRIo1aUtiWVYXZ7mk4+V4BjCGswF3IxTLJ+4RUta8ZiHh8lhkig2G8dya2eCcyR1dYUvzuV46EkJN8PSwww== + dependencies: + copy-anything "^3.0.5" + parse-node-version "^1.0.1" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + make-dir "^5.1.0" + mime "^1.4.1" + needle "^3.1.0" + probe-image-size "^7.2.3" + source-map "~0.6.0" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -7615,11 +9874,26 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash-es@^4.17.21: + version "4.18.1" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.18.1.tgz#b962eeb80d9d983a900bf342961fb7418ca10b1d" + integrity sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A== + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -7630,12 +9904,22 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.1.1, lodash@^4.17.15, lodash@^4.17.23, lodash@^4.17.4, lodash@^4.18.0: +lodash.upperfirst@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" + integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== + +lodash@^4.1.1, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.23, lodash@^4.17.4, lodash@^4.18.0, lodash@~4.17.15: version "4.18.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.18.1.tgz#ff2b66c1f6326d59513de2407bf881439812771c" integrity sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q== @@ -7650,7 +9934,7 @@ longest-streak@^3.0.0: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -7700,6 +9984,11 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" +make-dir@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-5.1.0.tgz#59b2d9acf7ffa543d14238617a697458fa8dd5c9" + integrity sha512-IfpFq6UM39dUNiphpA6uDezNx/AvWyhwfICWPR3t1VspkgkMZrL+Rk1RbN1bx+aeNYwOrqGJgEgV3yotk+ZUVw== + make-error@^1.1.1, make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -8264,6 +10553,11 @@ mime-types@^2.1.12, mime-types@^2.1.27: dependencies: mime-db "1.52.0" +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -8307,7 +10601,7 @@ minimatch@^9.0.4, minimatch@^9.0.5: dependencies: brace-expansion "^2.0.2" -minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -8317,6 +10611,11 @@ minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +mockdate@^3.0.2: + version "3.0.5" + resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb" + integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ== + moment-timezone@0.5.47: version "0.5.47" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.47.tgz#d4d1a21b78372d914d6d69ae285454732a429749" @@ -8334,6 +10633,18 @@ monaco-editor@0.34.1: resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87" integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ== +moo-color@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/moo-color/-/moo-color-1.0.3.tgz#d56435f8359c8284d83ac58016df7427febece74" + integrity sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ== + dependencies: + color-name "^1.1.4" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -8353,7 +10664,7 @@ nano-css@^5.6.2: stacktrace-js "^2.0.2" stylis "^4.3.0" -nanoid@^3.3.11, nanoid@~3.3.8: +nanoid@^3.3.11, nanoid@^3.3.16, nanoid@~3.3.8: version "3.3.12" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.12.tgz#ab3d912e217a6d0a514f00a72a16543a28982c05" integrity sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ== @@ -8363,6 +10674,23 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +needle@^2.5.2: + version "2.9.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +needle@^3.1.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-3.5.0.tgz#aa2023642cb41b11a11babb733fd8fa952919112" + integrity sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w== + dependencies: + iconv-lite "^0.6.3" + sax "^1.2.4" + neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -8381,6 +10709,16 @@ node-abort-controller@^3.0.1: resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== +node-exports-info@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/node-exports-info/-/node-exports-info-1.6.2.tgz#243a3105677d6781cd26e6a72350fd928a5cb46f" + integrity sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag== + dependencies: + array.prototype.flatmap "^1.3.3" + es-errors "^1.3.0" + object.entries "^1.1.9" + semver "^6.3.1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -8423,12 +10761,17 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" +numeral@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" + integrity sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA== + nwsapi@^2.2.12, nwsapi@^2.2.2: version "2.2.23" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.23.tgz#59712c3a88e6de2bb0b6ccc1070397267019cf6c" integrity sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ== -object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@4.x, 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== @@ -8451,7 +10794,7 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4, object.assign@^4.1.7: +object.assign@^4.1.2, object.assign@^4.1.4, object.assign@^4.1.7: version "4.1.7" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== @@ -8463,7 +10806,7 @@ object.assign@^4.1.4, object.assign@^4.1.7: has-symbols "^1.1.0" object-keys "^1.1.1" -object.entries@^1.1.9: +object.entries@^1.1.2, object.entries@^1.1.6, object.entries@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.9.tgz#e4770a6a1444afb61bd39f984018b5bede25f8b3" integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== @@ -8473,7 +10816,7 @@ object.entries@^1.1.9: define-properties "^1.2.1" es-object-atoms "^1.1.1" -object.fromentries@^2.0.8: +object.fromentries@^2.0.6, object.fromentries@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== @@ -8483,6 +10826,24 @@ object.fromentries@^2.0.8: es-abstract "^1.23.2" es-object-atoms "^1.0.0" +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.hasown@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" + integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== + dependencies: + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + object.values@^1.1.6, object.values@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" @@ -8518,7 +10879,7 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -optionator@^0.9.3: +optionator@^0.9.1, optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== @@ -8642,6 +11003,11 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-node-version@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + parse5@^7.0.0, parse5@^7.1.1, parse5@^7.1.2: version "7.3.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05" @@ -9020,6 +11386,15 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== +postcss@^8.4.31: + version "8.5.25" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.25.tgz#5012a598eaaa897f21bbe8553be3cb7bd2bd78cb" + integrity sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw== + dependencies: + nanoid "^3.3.16" + picocolors "^1.1.1" + source-map-js "^1.2.1" + postcss@^8.4.33, postcss@^8.4.43: version "8.5.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" @@ -9039,6 +11414,13 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prettier-linter-helpers@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz#6a31f88a4bad6c7adda253de12ba4edaea80ebcd" + integrity sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg== + dependencies: + fast-diff "^1.1.2" + prettier@^2.8.7: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" @@ -9049,15 +11431,6 @@ prettier@^3.2.5, prettier@^3.5.3: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173" integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg== -pretty-format@30.2.0, pretty-format@^30.0.0: - version "30.2.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.2.0.tgz#2d44fe6134529aed18506f6d11509d8a62775ebe" - integrity sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA== - dependencies: - "@jest/schemas" "30.0.5" - ansi-styles "^5.2.0" - react-is "^18.3.1" - pretty-format@^27.0.2: version "27.5.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" @@ -9089,6 +11462,20 @@ prismjs@1.30.0: resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9" integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== +probe-image-size@^7.2.3: + version "7.3.0" + resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-7.3.0.tgz#a07df2e2cffc1057026d5a1bda3a5b11ee970034" + integrity sha512-7CaDeBwiAbh6ohXsvLbAZhO7wzsZAmaevfxe39qvCwRh8LyaZfDlBGGLU1CCTgrTLtCOdwBBhjOrIHaIIimHfQ== + dependencies: + lodash.merge "^4.6.2" + needle "^2.5.2" + stream-parser "~0.3.1" + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + promise.series@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd" @@ -9102,7 +11489,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1: +prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, 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== @@ -9144,6 +11531,11 @@ proxy-from-env@^1.1.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + psl@^1.1.33: version "1.15.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" @@ -9193,7 +11585,7 @@ raf-schd@^4.0.3: resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== -raf@^3.1.0: +raf@^3.1.0, raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -9215,7 +11607,179 @@ rbush@^4.0.0: dependencies: quickselect "^3.0.0" -rc-overflow@^1.3.2: +rc-animate@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-3.1.1.tgz#defdd863f56816c222534e4dc68feddecd081386" + integrity sha512-8wg2Zg3EETy0k/9kYuis30NJNQg1D6/WSQwnCiz6SvyxQXNet/rVraRz3bPngwY6rcU2nlRvoShiYOorXyF7Sg== + dependencies: + "@ant-design/css-animation" "^1.7.2" + classnames "^2.2.6" + raf "^3.4.0" + rc-util "^4.15.3" + +rc-cascader@~3.34.0: + version "3.34.0" + resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.34.0.tgz#56f936ab6b1229bab7d558701ce9b9e96536582c" + integrity sha512-KpXypcvju9ptjW9FaN2NFcA2QH9E9LHKq169Y0eWtH4e/wHQ5Wh5qZakAgvb8EKZ736WZ3B0zLLOBsrsja5Dag== + dependencies: + "@babel/runtime" "^7.25.7" + classnames "^2.3.1" + rc-select "~14.16.2" + rc-tree "~5.13.0" + rc-util "^5.43.0" + +rc-checkbox@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/rc-checkbox/-/rc-checkbox-3.5.0.tgz#3ae2441e3a321774d390f76539e706864fcf5ff0" + integrity sha512-aOAQc3E98HteIIsSqm6Xk2FPKIER6+5vyEFMZfo73TqM+VVAIqOkHoPjgKLqSNtVLWScoaM7vY2ZrGEheI79yg== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.3.2" + rc-util "^5.25.2" + +rc-collapse@~3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-3.9.0.tgz#972404ce7724e1c9d1d2476543e1175404a36806" + integrity sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.3.4" + rc-util "^5.27.0" + +rc-dialog@~9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-9.6.0.tgz#dc7a255c6ad1cb56021c3a61c7de86ee88c7c371" + integrity sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg== + dependencies: + "@babel/runtime" "^7.10.1" + "@rc-component/portal" "^1.0.0-8" + classnames "^2.2.6" + rc-motion "^2.3.0" + rc-util "^5.21.0" + +rc-drawer@~7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-7.3.0.tgz#1bb5fe5f9da38b6a2b2a7dffc9fcb647252a328f" + integrity sha512-DX6CIgiBWNpJIMGFO8BAISFkxiuKitoizooj4BDyee8/SnBn0zwO2FHrNDpqqepj0E/TFTDpmEBCyFuTgC7MOg== + dependencies: + "@babel/runtime" "^7.23.9" + "@rc-component/portal" "^1.1.1" + classnames "^2.2.6" + rc-motion "^2.6.1" + rc-util "^5.38.1" + +rc-dropdown@~4.2.0, rc-dropdown@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/rc-dropdown/-/rc-dropdown-4.2.1.tgz#44729eb2a4272e0353d31ac060da21e606accb1c" + integrity sha512-YDAlXsPv3I1n42dv1JpdM7wJ+gSUBfeyPK59ZpBD9jQhK9jVuxpjj3NmWQHOBceA1zEPVX84T2wbdb2SD0UjmA== + dependencies: + "@babel/runtime" "^7.18.3" + "@rc-component/trigger" "^2.0.0" + classnames "^2.2.6" + rc-util "^5.44.1" + +rc-field-form@~2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-2.7.1.tgz#8bb1d7c6bf40e2b99b494816972252c327d9b5a0" + integrity sha512-vKeSifSJ6HoLaAB+B8aq/Qgm8a3dyxROzCtKNCsBQgiverpc4kWDQihoUwzUj+zNWJOykwSY4dNX3QrGwtVb9A== + dependencies: + "@babel/runtime" "^7.18.0" + "@rc-component/async-validator" "^5.0.3" + rc-util "^5.32.2" + +rc-form@^2.4.12: + version "2.4.12" + resolved "https://registry.yarnpkg.com/rc-form/-/rc-form-2.4.12.tgz#4ee8711e90a2584baa7ac276de96bee0d9b0f5f1" + integrity sha512-sHfyWRrnjCHkeCYfYAGop2GQBUC6CKMPcJF9h/gL/vTmZB/RN6fNOGKjXrXjFbwFwKXUWBoPtIDDDmXQW9xNdw== + dependencies: + async-validator "~1.11.3" + babel-runtime "6.x" + create-react-class "^15.5.3" + dom-scroll-into-view "1.x" + hoist-non-react-statics "^3.3.0" + lodash "^4.17.4" + rc-util "^4.15.3" + react-is "^16.13.1" + warning "^4.0.3" + +rc-image@~7.12.0: + version "7.12.0" + resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-7.12.0.tgz#95e9314701e668217d113c1f29b4f01ac025cafe" + integrity sha512-cZ3HTyyckPnNnUb9/DRqduqzLfrQRyi+CdHjdqgsyDpI3Ln5UX1kXnAhPBSJj9pVRzwRFgqkN7p9b6HBDjmu/Q== + dependencies: + "@babel/runtime" "^7.11.2" + "@rc-component/portal" "^1.0.2" + classnames "^2.2.6" + rc-dialog "~9.6.0" + rc-motion "^2.6.2" + rc-util "^5.34.1" + +rc-input-number@~9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-9.5.0.tgz#b47963d0f2cbd85ab2f1badfdc089a904c073f38" + integrity sha512-bKaEvB5tHebUURAEXw35LDcnRZLq3x1k7GxfAqBMzmpHkDGzjAtnUL8y4y5N15rIFIg5IJgwr211jInl3cipag== + dependencies: + "@babel/runtime" "^7.10.1" + "@rc-component/mini-decimal" "^1.0.1" + classnames "^2.2.5" + rc-input "~1.8.0" + rc-util "^5.40.1" + +rc-input@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/rc-input/-/rc-input-1.8.0.tgz#d2f4404befebf2fbdc28390d5494c302f74ae974" + integrity sha512-KXvaTbX+7ha8a/k+eg6SYRVERK0NddX8QX7a7AnRvUa/rEH0CNMlpcBzBkhI0wp2C8C4HlMoYl8TImSN+fuHKA== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-util "^5.18.1" + +rc-mentions@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-2.20.0.tgz#3bbeac0352b02e0ce3e1244adb48701bb6903bf7" + integrity sha512-w8HCMZEh3f0nR8ZEd466ATqmXFCMGMN5UFCzEUL0bM/nGw/wOS2GgRzKBcm19K++jDyuWCOJOdgcKGXU3fXfbQ== + dependencies: + "@babel/runtime" "^7.22.5" + "@rc-component/trigger" "^2.0.0" + classnames "^2.2.6" + rc-input "~1.8.0" + rc-menu "~9.16.0" + rc-textarea "~1.10.0" + rc-util "^5.34.1" + +rc-menu@~9.16.0, rc-menu@~9.16.1: + version "9.16.1" + resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.16.1.tgz#9df1168e41d87dc7164c582173e1a1d32011899f" + integrity sha512-ghHx6/6Dvp+fw8CJhDUHFHDJ84hJE3BXNCzSgLdmNiFErWSOaZNsihDAsKq9ByTALo/xkNIwtDFGIl6r+RPXBg== + dependencies: + "@babel/runtime" "^7.10.1" + "@rc-component/trigger" "^2.0.0" + classnames "2.x" + rc-motion "^2.4.3" + rc-overflow "^1.3.1" + rc-util "^5.27.0" + +rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.3, rc-motion@^2.4.4, rc-motion@^2.6.1, rc-motion@^2.6.2, rc-motion@^2.9.0, rc-motion@^2.9.5: + version "2.9.5" + resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.9.5.tgz#12c6ead4fd355f94f00de9bb4f15df576d677e0c" + integrity sha512-w+XTUrfh7ArbYEd2582uDrEhmBHwK1ZENJiSJVb7uRxdE7qJSYjbO2eksRXmndqyKqKoYPc9ClpPh5242mV1vA== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-util "^5.44.0" + +rc-notification@~5.6.4: + version "5.6.4" + resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-5.6.4.tgz#ea89c39c13cd517fdfd97fe63f03376fabb78544" + integrity sha512-KcS4O6B4qzM3KH7lkwOB7ooLPZ4b6J+VMmQgT51VZCeEcmghdeR4IrMcFq0LG+RPdnbe/ArT086tGM8Snimgiw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.9.0" + rc-util "^5.20.1" + +rc-overflow@^1.3.1, rc-overflow@^1.3.2: version "1.5.0" resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.5.0.tgz#02e58a15199e392adfcc87e0d6e9e7c8e57f2771" integrity sha512-Lm/v9h0LymeUYJf0x39OveU52InkdRXqnn2aYXfWmo8WdOonIKB2kfau+GF0fWq6jPgtdO9yMqveGcK6aIhJmg== @@ -9225,7 +11789,46 @@ rc-overflow@^1.3.2: rc-resize-observer "^1.0.0" rc-util "^5.37.0" -rc-resize-observer@^1.0.0: +rc-pagination@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-5.1.0.tgz#a6e63a2c5db29e62f991282eb18a2d3ee725ba8b" + integrity sha512-8416Yip/+eclTFdHXLKTxZvn70duYVGTvUUWbckCCZoIl3jagqke3GLsFrMs0bsQBikiYpZLD9206Ej4SOdOXQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.3.2" + rc-util "^5.38.0" + +rc-picker@~4.11.3: + version "4.11.3" + resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-4.11.3.tgz#7e7e3ad83aa461c284b8391c697492d1c34d2cb8" + integrity sha512-MJ5teb7FlNE0NFHTncxXQ62Y5lytq6sh5nUw0iH8OkHL/TjARSEvSHpr940pWgjGANpjCwyMdvsEV55l5tYNSg== + dependencies: + "@babel/runtime" "^7.24.7" + "@rc-component/trigger" "^2.0.0" + classnames "^2.2.1" + rc-overflow "^1.3.2" + rc-resize-observer "^1.4.0" + rc-util "^5.43.0" + +rc-progress@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-4.0.0.tgz#5382147d9add33d3a5fbd264001373df6440e126" + integrity sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.6" + rc-util "^5.16.1" + +rc-rate@~2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/rc-rate/-/rc-rate-2.13.1.tgz#29af7a3d4768362e9d4388f955a8b6389526b7fd" + integrity sha512-QUhQ9ivQ8Gy7mtMZPAjLbxBt5y9GRp65VcUyGUMF3N3fhiftivPHdpuDIaWIMOTEprAjZPC08bls1dQB+I1F2Q== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.0.1" + +rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0, rc-resize-observer@^1.3.1, rc-resize-observer@^1.4.0, rc-resize-observer@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.4.3.tgz#4fd41fa561ba51362b5155a07c35d7c89a1ea569" integrity sha512-YZLjUbyIWox8E9i9C3Tm7ia+W7euPItNWSPX5sCcQTYbnwDb5uNpnLHQCG1f22oZWUhLw4Mv2tFmeWe68CDQRQ== @@ -9235,7 +11838,145 @@ rc-resize-observer@^1.0.0: rc-util "^5.44.1" resize-observer-polyfill "^1.5.1" -rc-util@^5.37.0, rc-util@^5.44.1: +rc-segmented@~2.7.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.7.1.tgz#08a598b14e755117c5b37d238955c2d50eaa5d33" + integrity sha512-izj1Nw/Dw2Vb7EVr+D/E9lUTkBe+kKC+SAFSU9zqr7WV2W5Ktaa9Gc7cB2jTqgk8GROJayltaec+DBlYKc6d+g== + dependencies: + "@babel/runtime" "^7.11.1" + classnames "^2.2.1" + rc-motion "^2.4.4" + rc-util "^5.17.0" + +rc-select@~14.16.2, rc-select@~14.16.8: + version "14.16.8" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.16.8.tgz#78e6782f1ccc1f03d9003bc3effa4ed609d29a97" + integrity sha512-NOV5BZa1wZrsdkKaiK7LHRuo5ZjZYMDxPP6/1+09+FB4KoNi8jcG1ZqLE3AVCxEsYMBe65OBx71wFoHRTP3LRg== + dependencies: + "@babel/runtime" "^7.10.1" + "@rc-component/trigger" "^2.1.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-overflow "^1.3.1" + rc-util "^5.16.1" + rc-virtual-list "^3.5.2" + +rc-slider@~11.1.9: + version "11.1.9" + resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-11.1.9.tgz#d872130fbf4ec51f28543d62e90451091d6f5208" + integrity sha512-h8IknhzSh3FEM9u8ivkskh+Ef4Yo4JRIY2nj7MrH6GQmrwV6mcpJf5/4KgH5JaVI1H3E52yCdpOlVyGZIeph5A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.5" + rc-util "^5.36.0" + +rc-steps@~6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/rc-steps/-/rc-steps-6.0.1.tgz#c2136cd0087733f6d509209a84a5c80dc29a274d" + integrity sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g== + dependencies: + "@babel/runtime" "^7.16.7" + classnames "^2.2.3" + rc-util "^5.16.1" + +rc-switch@~4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rc-switch/-/rc-switch-4.1.0.tgz#f37d81b4e0c5afd1274fd85367b17306bf25e7d7" + integrity sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg== + dependencies: + "@babel/runtime" "^7.21.0" + classnames "^2.2.1" + rc-util "^5.30.0" + +rc-table@~7.54.0: + version "7.54.0" + resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.54.0.tgz#dedd4ea18d1189f2acdf90a80f04d8ca0111e16a" + integrity sha512-/wDTkki6wBTjwylwAGjpLKYklKo9YgjZwAU77+7ME5mBoS32Q4nAwoqhA2lSge6fobLW3Tap6uc5xfwaL2p0Sw== + dependencies: + "@babel/runtime" "^7.10.1" + "@rc-component/context" "^1.4.0" + classnames "^2.2.5" + rc-resize-observer "^1.1.0" + rc-util "^5.44.3" + rc-virtual-list "^3.14.2" + +rc-tabs@~15.7.0: + version "15.7.0" + resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-15.7.0.tgz#14ca2ee6213d00491a8b67ae26e2d35c256bf19a" + integrity sha512-ZepiE+6fmozYdWf/9gVp7k56PKHB1YYoDsKeQA1CBlJ/POIhjkcYiv0AGP0w2Jhzftd3AVvZP/K+V+Lpi2ankA== + dependencies: + "@babel/runtime" "^7.11.2" + classnames "2.x" + rc-dropdown "~4.2.0" + rc-menu "~9.16.0" + rc-motion "^2.6.2" + rc-resize-observer "^1.0.0" + rc-util "^5.34.1" + +rc-textarea@~1.10.0, rc-textarea@~1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-1.10.2.tgz#459e3574a95c32939c6793045a1e4db04cb514cc" + integrity sha512-HfaeXiaSlpiSp0I/pvWpecFEHpVysZ9tpDLNkxQbMvMz6gsr7aVZ7FpWP9kt4t7DB+jJXesYS0us1uPZnlRnwQ== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "^2.2.1" + rc-input "~1.8.0" + rc-resize-observer "^1.0.0" + rc-util "^5.27.0" + +rc-tooltip@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-6.4.0.tgz#e832ed0392872025e59928cfc1ad9045656467fd" + integrity sha512-kqyivim5cp8I5RkHmpsp1Nn/Wk+1oeloMv9c7LXNgDxUpGm+RbXJGL+OPvDlcRnx9DBeOe4wyOIl4OKUERyH1g== + dependencies: + "@babel/runtime" "^7.11.2" + "@rc-component/trigger" "^2.0.0" + classnames "^2.3.1" + rc-util "^5.44.3" + +rc-tree-select@~5.27.0: + version "5.27.0" + resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-5.27.0.tgz#3daa62972ae80846dac96bf4776d1a9dc9c7c4c6" + integrity sha512-2qTBTzwIT7LRI1o7zLyrCzmo5tQanmyGbSaGTIf7sYimCklAToVVfpMC6OAldSKolcnjorBYPNSKQqJmN3TCww== + dependencies: + "@babel/runtime" "^7.25.7" + classnames "2.x" + rc-select "~14.16.2" + rc-tree "~5.13.0" + rc-util "^5.43.0" + +rc-tree@~5.13.0, rc-tree@~5.13.1: + version "5.13.1" + resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-5.13.1.tgz#f36a33a94a1282f4b09685216c01487089748910" + integrity sha512-FNhIefhftobCdUJshO7M8uZTA9F4OPGVXqGfZkkD/5soDeOhwO06T/aKTrg0WD8gRg/pyfq+ql3aMymLHCTC4A== + dependencies: + "@babel/runtime" "^7.10.1" + classnames "2.x" + rc-motion "^2.0.1" + rc-util "^5.16.1" + rc-virtual-list "^3.5.1" + +rc-upload@~4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.11.0.tgz#c2ced905a8b38b3e5c48493d388ca0e8373de18b" + integrity sha512-ZUyT//2JAehfHzjWowqROcwYJKnZkIUGWaTE/VogVrepSl7AFNbQf4+zGfX4zl9Vrj/Jm8scLO0R6UlPDKK4wA== + dependencies: + "@babel/runtime" "^7.18.3" + classnames "^2.2.5" + rc-util "^5.2.0" + +rc-util@^4.15.3: + version "4.21.1" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.21.1.tgz#88602d0c3185020aa1053d9a1e70eac161becb05" + integrity sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg== + dependencies: + add-dom-event-listener "^1.1.0" + prop-types "^15.5.10" + react-is "^16.12.0" + react-lifecycles-compat "^3.0.4" + shallowequal "^1.1.0" + +rc-util@^5.0.1, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.2.0, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.24.4, rc-util@^5.24.5, rc-util@^5.25.2, rc-util@^5.27.0, rc-util@^5.30.0, rc-util@^5.31.1, rc-util@^5.32.2, rc-util@^5.34.1, rc-util@^5.35.0, rc-util@^5.36.0, rc-util@^5.37.0, rc-util@^5.38.0, rc-util@^5.38.1, rc-util@^5.40.1, rc-util@^5.43.0, rc-util@^5.44.0, rc-util@^5.44.1, rc-util@^5.44.3, rc-util@^5.44.4: version "5.44.4" resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.44.4.tgz#89ee9037683cca01cd60f1a6bbda761457dd6ba5" integrity sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w== @@ -9243,6 +11984,26 @@ rc-util@^5.37.0, rc-util@^5.44.1: "@babel/runtime" "^7.18.3" react-is "^18.2.0" +rc-virtual-list@^3.14.2, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2: + version "3.19.2" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.19.2.tgz#1dd2d782c9a3ccbe537bb873447d73f83af8de0f" + integrity sha512-Ys6NcjwGkuwkeaWBDqfI3xWuZ7rDiQXlH1o2zLfFzATfEgXcqpk8CkgMfbJD81McqjcJVez25a3kPxCR807evA== + dependencies: + "@babel/runtime" "^7.20.0" + classnames "^2.2.6" + rc-resize-observer "^1.0.0" + rc-util "^5.36.0" + +react-base16-styling@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.10.0.tgz#5d5f019bd4dc5870c3e92fd9d5410533a0bbb0c6" + integrity sha512-H1k2eFB6M45OaiRru3PBXkuCcn2qNmx+gzLb4a9IPMR7tMH8oBRXU5jGbPDYG1Hz+82d88ED0vjR8BmqU3pQdg== + dependencies: + "@types/lodash" "^4.17.0" + color "^4.2.3" + csstype "^3.1.3" + lodash-es "^4.17.21" + react-calendar@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-6.0.0.tgz#3b13a9e80832fe51fdebc6afdcd2285ac851926f" @@ -9253,6 +12014,11 @@ react-calendar@^6.0.0: get-user-locale "^3.0.0" warning "^4.0.0" +react-chartjs-2@^4.0.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz#9941e7397fb963f28bb557addb401e9ff96c6681" + integrity sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA== + react-colorful@5.6.1: version "5.6.1" resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b" @@ -9273,7 +12039,7 @@ react-data-grid@grafana/react-data-grid#a10c748f40edc538425b458af4e471a8262ec4ed dependencies: clsx "^2.0.0" -react-dom@^18.2.0, react-dom@^18.3.1: +react-dom@^18.2.0, react-dom@^18.3.1, react-dom@~16.12.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -9290,6 +12056,13 @@ react-dropzone@14.3.8: file-selector "^2.1.0" prop-types "^15.8.1" +react-final-form@^6.5.3: + version "6.5.9" + resolved "https://registry.yarnpkg.com/react-final-form/-/react-final-form-6.5.9.tgz#644797d4c122801b37b58a76c87761547411190b" + integrity sha512-x3XYvozolECp3nIjly+4QqxdjSSWfcnpGEL5K8OBT6xmGrq5kBqbA6+/tOqoom9NwqIPPbxPNsOViFlbKgowbA== + dependencies: + "@babel/runtime" "^7.15.4" + react-from-dom@^0.7.5: version "0.7.5" resolved "https://registry.yarnpkg.com/react-from-dom/-/react-from-dom-0.7.5.tgz#2d2d2bf6d80149c053bcf71bb6615e5e7f6d23db" @@ -9313,6 +12086,15 @@ react-hook-form@^7.71.2: resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.75.0.tgz#4364affb4af39e45eeb7e3c6e10f6579cdcca7a2" integrity sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw== +react-horizontal-stacked-bar-chart@^8.15.2: + version "8.15.2" + resolved "https://registry.yarnpkg.com/react-horizontal-stacked-bar-chart/-/react-horizontal-stacked-bar-chart-8.15.2.tgz#934c281381fa6f50b07297183fc342d93195e42e" + integrity sha512-O/Xh8ttgjFdJwCgDdZFSMyv8Ia032Sc/14XM8nkcbRyQAopSccxLAB8cxJMY1ZZUt8IoBKVu2JcbcKXTQy7JWg== + dependencies: + lodash "~4.17.15" + react "~16.12.0" + react-dom "~16.12.0" + react-i18next@^15.0.0: version "15.7.4" resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-15.7.4.tgz#146e50f220d204b842e22c75d1a3d23c6c589a30" @@ -9340,12 +12122,12 @@ react-is@18.2.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-is@18.3.1, react-is@^18.0.0, react-is@^18.2.0, react-is@^18.3.1: +react-is@18.3.1, react-is@^18.0.0, react-is@^18.2.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -react-is@^16.13.1, react-is@^16.7.0: +react-is@^16.12.0, 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== @@ -9360,6 +12142,11 @@ react-is@^19.2.3: resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.7.tgz#57668ee86a78574a542b0a539455212b2c086df2" integrity sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A== +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== + react-loading-skeleton@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/react-loading-skeleton/-/react-loading-skeleton-3.5.0.tgz#da2090355b4dedcad5c53cb3f0ed364e3a76d6ca" @@ -9399,7 +12186,7 @@ react-router-dom-v5-compat@^6.26.1: history "^5.3.0" react-router "6.30.0" -react-router-dom@5.3.4, react-router-dom@6.30.2, react-router-dom@^6.30.2: +react-router-dom@5.3.4, react-router-dom@6.30.2, react-router-dom@^6.22.0, react-router-dom@^6.30.2: version "6.30.2" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.30.2.tgz#ee8c161bce4890d34484b552f8510f9af0e22b01" integrity sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q== @@ -9429,11 +12216,36 @@ react-select@5.10.2: react-transition-group "^4.3.0" use-isomorphic-layout-effect "^1.2.0" -react-table@7.8.0: +react-split-pane@^0.1.91: + version "0.1.92" + resolved "https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.92.tgz#68242f72138aed95dd5910eeb9d99822c4fc3a41" + integrity sha512-GfXP1xSzLMcLJI5BM36Vh7GgZBpy+U/X0no+VM3fxayv+p1Jly5HpMofZJraeaMl73b3hvlr+N9zJKvLB/uz9w== + dependencies: + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.4" + react-style-proptype "^3.2.2" + +react-style-proptype@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-style-proptype/-/react-style-proptype-3.2.2.tgz#d8e998e62ce79ec35b087252b90f19f1c33968a0" + integrity sha512-ywYLSjNkxKHiZOqNlso9PZByNEY+FTyh3C+7uuziK0xFXu9xzdyfHwg4S9iyiRRoPCR4k2LqaBBsWVmSBwCWYQ== + dependencies: + prop-types "^15.5.4" + +react-table@7.8.0, react-table@^7.6.2: version "7.8.0" resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.8.0.tgz#07858c01c1718c09f7f1aed7034fcfd7bda907d2" integrity sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA== +react-textarea-autosize@~8.5.9: + version "8.5.9" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.9.tgz#ab8627b09aa04d8a2f45d5b5cd94c84d1d4a8893" + integrity sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A== + dependencies: + "@babel/runtime" "^7.20.13" + use-composed-ref "^1.3.0" + use-latest "^1.2.1" + 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" @@ -9469,6 +12281,11 @@ react-use@17.6.0: ts-easing "^0.2.0" tslib "^2.1.0" +react-viewport-list@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/react-viewport-list/-/react-viewport-list-7.1.2.tgz#095a32c60dfa545cf67141f68478fd9e0b8cc852" + integrity sha512-CfmkYyoFufSdJ95nTgENAHtWOn1XwxcUZPBSueOPzOvz59A31qHgYpADYuiSUfZ5ypR3MfyWMUgRAOMsNDDl8Q== + react-window@1.8.11: version "1.8.11" resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.11.tgz#a857b48fa85bd77042d59cc460964ff2e0648525" @@ -9477,7 +12294,7 @@ react-window@1.8.11: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" -react@^18.2.0, react@^18.3.1: +react@^18.2.0, react@^18.3.1, react@~16.12.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -9525,6 +12342,23 @@ reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: get-proto "^1.0.1" which-builtin-type "^1.2.1" +regenerate-unicode-properties@^10.2.2: + version "10.2.2" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz#aa113812ba899b630658c7623466be71e1f86f66" + integrity sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" @@ -9537,6 +12371,35 @@ regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.3, regexp.prototype.f gopd "^1.2.0" set-function-name "^2.0.2" +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^6.3.1: + version "6.4.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.4.0.tgz#3580ce0c4faedef599eccb146612436b62a176e5" + integrity sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.2.2" + regjsgen "^0.8.0" + regjsparser "^0.13.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.2.1" + +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.13.0: + version "0.13.2" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.13.2.tgz#f654734b5c588b22ba3e21693b30523417180808" + integrity sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ== + dependencies: + jsesc "~3.1.0" + rehype-raw@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-7.0.0.tgz#59d7348fd5dbef3807bbaa1d443efd2dd85ecee4" @@ -9661,6 +12524,28 @@ resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.11: + version "1.22.12" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.12.tgz#f5b2a680897c69c238a13cd16b15671f8b73549f" + integrity sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA== + dependencies: + es-errors "^1.3.0" + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.4, resolve@^2.0.0-next.6: + version "2.0.0-next.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.7.tgz#ba3b035d4b1ee7c522426eee73cabcb0fd5515dd" + integrity sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ== + dependencies: + es-errors "^1.3.0" + is-core-module "^2.16.2" + node-exports-info "^1.6.0" + object-keys "^1.1.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.5: version "2.0.0-next.5" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" @@ -9838,7 +12723,7 @@ safe-push-apply@^1.0.0: es-errors "^1.3.0" isarray "^2.0.5" -safe-regex-test@^1.1.0: +safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== @@ -9847,7 +12732,7 @@ safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -"safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -9869,6 +12754,11 @@ sass@1.63.2: immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" +sax@^1.2.4: + version "1.6.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.6.1.tgz#4c23cf608c0b693ab54b4b5888e92cfe977b9843" + integrity sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q== + sax@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/sax/-/sax-1.5.0.tgz#b5549b671069b7aa392df55ec7574cf411179eb8" @@ -9912,6 +12802,18 @@ screenfull@^5.1.0: resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== +scroll-into-view-if-needed@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz#fa9524518c799b45a2ef6bbffb92bcad0296d01f" + integrity sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ== + dependencies: + compute-scroll-into-view "^3.0.2" + +scroll-into-view@^1.14.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/scroll-into-view/-/scroll-into-view-1.16.2.tgz#ea3e810dacc861fb9c115eac7bf603e564f0104a" + integrity sha512-vyTE0i27o6eldt9xinjHec41Dw05y+faoI+s2zNKJAVOdbA5M2XZrYq/obJ8E+QDQulJ2gDjgui9w9m9RZSRng== + selection-is-backward@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/selection-is-backward/-/selection-is-backward-1.0.0.tgz#97a54633188a511aba6419fc5c1fa91b467e6be1" @@ -9922,6 +12824,11 @@ semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.2.1, semver@^7.3.2: + version "7.8.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69" + integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA== + semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3, semver@^7.7.0, semver@^7.7.3: version "7.7.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" @@ -9980,6 +12887,11 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -9992,6 +12904,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-quote@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.9.0.tgz#e108b1a136586d5964edb3300016d4bedba0fe57" + integrity sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA== + side-channel-list@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" @@ -10047,6 +12964,28 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-swizzle@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.4.tgz#a8d11a45a11600d6a1ecdff6363329e3648c3667" + integrity sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw== + dependencies: + is-arrayish "^0.3.1" + +simplebar-core@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/simplebar-core/-/simplebar-core-1.3.2.tgz#e249caf38625afb7c316b2d219b66afd6227e301" + integrity sha512-qKgTTuTqapjsFGkNhCjyPhysnbZGpQqNmjk0nOYjFN5ordC/Wjvg+RbYCyMSnW60l/Z0ZS82GbNltly6PMUH1w== + dependencies: + lodash "^4.17.21" + lodash-es "^4.17.21" + +simplebar-react@^3.0.0-beta.8: + version "3.3.2" + resolved "https://registry.yarnpkg.com/simplebar-react/-/simplebar-react-3.3.2.tgz#699c9837f4ada71335b3eca9f8a2b788a559bda1" + integrity sha512-ZsgcQhKLtt5ra0BRIJeApfkTBQCa1vUPA/WXI4HcYReFt+oCEOvdVz6rR/XsGJcKxTlCRPmdGx1uJIUChupo+A== + dependencies: + simplebar-core "^1.3.2" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -10135,6 +13074,15 @@ slate@0.47.9: tiny-warning "^0.0.3" type-of "^2.0.1" +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + smob@^1.0.0: version "1.5.0" resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" @@ -10179,7 +13127,7 @@ source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -10194,6 +13142,14 @@ spdx-exceptions@^2.1.0: resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== +spdx-expression-parse@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + spdx-expression-parse@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz#a23af9f3132115465dac215c099303e4ceac5794" @@ -10212,6 +13168,13 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +sql-formatter@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/sql-formatter/-/sql-formatter-2.3.4.tgz#85ff9a946d8157e3917c0b1db514ca8184a1b6f1" + integrity sha512-CajWtvzYoBJbD5PQeVe3E7AOHAIYvRQEPOKgF9kfKNeY8jtjBiiA6pDzkMuAID8jJMluoPvyKveLigSaA5tKQQ== + dependencies: + lodash "^4.17.20" + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -10224,7 +13187,7 @@ stack-generator@^2.0.5: dependencies: stackframe "^1.3.4" -stack-utils@^2.0.3, stack-utils@^2.0.6: +stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== @@ -10276,6 +13239,18 @@ stop-iteration-iterator@^1.0.0, stop-iteration-iterator@^1.1.0: es-errors "^1.3.0" internal-slot "^1.1.0" +stream-parser@~0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773" + integrity sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ== + dependencies: + debug "2" + +string-convert@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" + integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== + string-hash@^1.1.1, string-hash@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" @@ -10321,7 +13296,16 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.matchall@^4.0.12: +string.prototype.includes@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92" + integrity sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + +string.prototype.matchall@^4.0.12, string.prototype.matchall@^4.0.8: version "4.0.12" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== @@ -10414,6 +13398,11 @@ strip-ansi@^7.0.1: dependencies: ansi-regex "^6.0.1" +strip-bom@^3.0.0: + version "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" @@ -10436,7 +13425,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -10483,20 +13472,32 @@ stylis@^4.3.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320" integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ== -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" +stylis@^4.3.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.4.0.tgz#c5846c9345f4bfc51bd0cbd7ca35a0744f485a5d" + integrity sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA== -supports-color@^8.0.0: +supports-color@8.1.1, supports-color@^8.0.0: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -10537,6 +13538,17 @@ tabbable@^6.0.0: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.4.0.tgz#36eb7a06d80b3924a22095daf45740dea3bf5581" integrity sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg== +table@^6.0.9: + version "6.9.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.9.0.tgz#50040afa6264141c7566b3b81d4d82c47a8668f5" + integrity sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + tapable@^2.2.1, tapable@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.0.tgz#7e3ea6d5ca31ba8e078b560f0d83ce9a14aa8be6" @@ -10582,6 +13594,11 @@ throttle-debounce@^3.0.1: resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== +throttle-debounce@^5.0.0, throttle-debounce@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-5.0.2.tgz#ec5549d84e053f043c9fd0f2a6dd892ff84456b1" + integrity sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A== + tiny-invariant@^1.0.1, tiny-invariant@^1.0.2, tiny-invariant@^1.0.6: version "1.3.3" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" @@ -10647,6 +13664,13 @@ tinyspy@^3.0.2: resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== +tippy.js@^6.3.1, tippy.js@^6.3.7: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -10707,6 +13731,11 @@ tr46@^5.1.0: dependencies: punycode "^2.3.1" +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + trim-lines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" @@ -10747,7 +13776,7 @@ ts-jest@^29.4.9: type-fest "^4.41.0" yargs-parser "^21.1.1" -ts-node@^10.9.2: +ts-node@^10.9.1, ts-node@^10.9.2: version "10.9.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== @@ -10771,6 +13800,30 @@ tsconfck@^3.0.3: resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-3.1.6.tgz#da1f0b10d82237ac23422374b3fce1edb23c3ead" integrity sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w== +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tsconfig-paths@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@2.5.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" + integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== + tslib@2.8.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.6.2, tslib@^2.7.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" @@ -10781,7 +13834,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tsutils@^3.21.0: +tsutils@^3.17.1, tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== @@ -10912,6 +13965,16 @@ typed-assert@^1.0.8: resolved "https://registry.yarnpkg.com/typed-assert/-/typed-assert-1.0.9.tgz#8af9d4f93432c4970ec717e3006f33f135b06213" integrity sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg== +typescript@4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + +typescript@5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + typescript@5.5.4: version "5.5.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" @@ -10962,6 +14025,29 @@ undici-types@~7.16.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" + integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz#65a7adfad8574c219890e219285ce4c64ed67eaa" + integrity sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz#301d4f8a43d2b75c97adfad87c9dd5350c9475d1" + integrity sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ== + unified@^11.0.0: version "11.0.5" resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" @@ -11058,11 +14144,23 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -use-isomorphic-layout-effect@^1.2.0: +use-composed-ref@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.4.0.tgz#09e023bf798d005286ad85cd20674bdf5770653b" + integrity sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w== + +use-isomorphic-layout-effect@^1.1.1, use-isomorphic-layout-effect@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz#2f11a525628f56424521c748feabc2ffcc962fce" integrity sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA== +use-latest@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.3.0.tgz#549b9b0d4c1761862072f0899c6f096eb379137a" + integrity sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ== + dependencies: + use-isomorphic-layout-effect "^1.1.1" + use-sync-external-store@^1.4.0: version "1.6.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" @@ -11078,6 +14176,11 @@ uuid@11.1.0, uuid@^11.0.2, uuid@^11.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uwrap@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/uwrap/-/uwrap-0.1.2.tgz#2a5da1977ef85394ad76a64544988fc2f00a297c" @@ -11088,6 +14191,11 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +v8-compile-cache@^2.0.3: + version "2.4.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" + integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== + v8-to-istanbul@^9.0.1: version "9.3.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" @@ -11218,7 +14326,7 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -warning@^4.0.0: +warning@^4.0.0, warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== @@ -11583,7 +14691,7 @@ yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.3.1: +yargs@17.7.2, yargs@^17.3.1: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From 9e6976ba896e11e687bb62990006309723fac70a Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Tue, 4 Aug 2026 10:31:43 +0100 Subject: [PATCH 08/10] chore: improve dashboards reload time --- .devcontainer/Makefile | 8 +++++++- dev/grafana-dashboards-provisioning.yml | 10 ++++++++++ docker-compose.dev.yml | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 dev/grafana-dashboards-provisioning.yml diff --git a/.devcontainer/Makefile b/.devcontainer/Makefile index e6b70c6ad09..b507efce9df 100644 --- a/.devcontainer/Makefile +++ b/.devcontainer/Makefile @@ -61,8 +61,14 @@ run-all: run-agent-ci run-managed-ci run-qan-ci run-vmproxy-ci ## Run all go ser run: run-all ## Aliased to "run-all" echo "run is aliased to run-all" -ui-setup: ## Install UI dependencies +UI_INSTALL_STAMP := ui/node_modules/.install.stamp +UI_DEPS := ui/package.json ui/yarn.lock $(wildcard ui/apps/*/package.json) $(wildcard ui/packages/*/package.json) + +ui-setup: $(UI_INSTALL_STAMP) ## Install UI dependencies (skips yarn install if deps are unchanged) + +$(UI_INSTALL_STAMP): $(UI_DEPS) cd ui && yarn install + @mkdir -p ui/node_modules && touch $@ run-ui: ui-setup setup-livereload ## Start vite dev server for UI with HMR, QAN webpack watch and dashboard JSON sync mv /srv/grafana/plugins/pmm-compat-app /srv/grafana/plugins/pmm-compat-app.bak; \ diff --git a/dev/grafana-dashboards-provisioning.yml b/dev/grafana-dashboards-provisioning.yml new file mode 100644 index 00000000000..7f32cb695ca --- /dev/null +++ b/dev/grafana-dashboards-provisioning.yml @@ -0,0 +1,10 @@ +apiVersion: 1 + +providers: + - name: 'percona_dashboards' + orgId: 1 + type: file + updateIntervalSeconds: 5 + options: + path: /usr/share/percona-dashboards/panels/pmm-app/dist/dashboards/ + foldersFromFilesStructure: true diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index f74e9f2eb3c..ae884bd7493 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -52,6 +52,8 @@ services: - ./managed/data/alerting-templates/:/usr/local/percona/alerting-templates/ # nginx config overrides - ./build/ansible/roles/nginx/files/conf.d/pmm.conf:/etc/nginx/conf.d/pmm.conf:ro + # faster dashboard provisioning polling for dev (default is 60s) + - ./dev/grafana-dashboards-provisioning.yml:/usr/share/grafana/conf/provisioning/dashboards/default.yml:ro # percona-ui # - ../percona-ui:/root/go/src/github.com/percona/percona-ui # grafana From 04ba11b65b9f1af19695dfa10a71f0f799fabff7 Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Sun, 9 Aug 2026 00:36:17 +0100 Subject: [PATCH 09/10] chore: project k8s namespace into pods and UI --- api/ha/v1beta1/ha.pb.go | 18 ++++++++--- api/ha/v1beta1/ha.pb.validate.go | 2 ++ api/ha/v1beta1/ha.proto | 3 ++ .../client/ha_service/status_responses.go | 4 +++ api/ha/v1beta1/json/v1beta1.json | 5 +++ api/swagger/swagger-dev.json | 5 +++ api/swagger/swagger.json | 5 +++ managed/cmd/pmm-managed/main.go | 5 +++ managed/models/params.go | 2 ++ managed/services/ha/ha.go | 2 +- managed/services/ha/haservice.go | 22 +++++++++++++ managed/services/ha/haservice_test.go | 32 +++++++++++++++++++ ui/apps/pmm/src/hooks/api/useHA.ts | 1 + ui/apps/pmm/src/types/ha.types.ts | 2 ++ 14 files changed, 103 insertions(+), 5 deletions(-) diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index 644ec65f4b2..a32c365477d 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -267,7 +267,10 @@ func (*StatusRequest) Descriptor() ([]byte, []int) { type StatusResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // Status of HA mode: "Enabled" or "Disabled". - Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + // Kubernetes namespace this instance is running in. Empty if unknown + // (e.g. non-Kubernetes installs). + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -309,6 +312,13 @@ func (x *StatusResponse) GetStatus() string { return "" } +func (x *StatusResponse) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + var File_ha_v1beta1_ha_proto protoreflect.FileDescriptor const file_ha_v1beta1_ha_proto_rawDesc = "" + @@ -323,9 +333,10 @@ const file_ha_v1beta1_ha_proto_rawDesc = "" + "\x11ListNodesResponse\x12(\n" + "\x05nodes\x18\x01 \x03(\v2\x12.ha.v1beta1.HANodeR\x05nodes\x12%\n" + "\x0eexpected_nodes\x18\x02 \x01(\x05R\rexpectedNodes\"\x0f\n" + - "\rStatusRequest\"(\n" + + "\rStatusRequest\"F\n" + "\x0eStatusResponse\x12\x16\n" + - "\x06status\x18\x01 \x01(\tR\x06status*S\n" + + "\x06status\x18\x01 \x01(\tR\x06status\x12\x1c\n" + + "\tnamespace\x18\x02 \x01(\tR\tnamespace*S\n" + "\bNodeRole\x12\x19\n" + "\x15NODE_ROLE_UNSPECIFIED\x10\x00\x12\x14\n" + "\x10NODE_ROLE_LEADER\x10\x01\x12\x16\n" + @@ -361,7 +372,6 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) - var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/ha/v1beta1/ha.pb.validate.go b/api/ha/v1beta1/ha.pb.validate.go index bf1c6293767..602aede93cc 100644 --- a/api/ha/v1beta1/ha.pb.validate.go +++ b/api/ha/v1beta1/ha.pb.validate.go @@ -505,6 +505,8 @@ func (m *StatusResponse) validate(all bool) error { // no validation rules for Status + // no validation rules for Namespace + if len(errors) > 0 { return StatusResponseMultiError(errors) } diff --git a/api/ha/v1beta1/ha.proto b/api/ha/v1beta1/ha.proto index ef1c88e8bd9..df7c8c90052 100644 --- a/api/ha/v1beta1/ha.proto +++ b/api/ha/v1beta1/ha.proto @@ -36,6 +36,9 @@ message StatusRequest {} message StatusResponse { // Status of HA mode: "Enabled" or "Disabled". string status = 1; + // Kubernetes namespace this instance is running in. Empty if unknown + // (e.g. non-Kubernetes installs). + string namespace = 2; } // HAService provides High Availability cluster status information. diff --git a/api/ha/v1beta1/json/client/ha_service/status_responses.go b/api/ha/v1beta1/json/client/ha_service/status_responses.go index 573ac666934..8f798f30da0 100644 --- a/api/ha/v1beta1/json/client/ha_service/status_responses.go +++ b/api/ha/v1beta1/json/client/ha_service/status_responses.go @@ -419,6 +419,10 @@ swagger:model StatusOKBody type StatusOKBody struct { // Status of HA mode: "Enabled" or "Disabled". Status string `json:"status,omitempty"` + + // Kubernetes namespace this instance is running in. Empty if unknown + // (e.g. non-Kubernetes installs). + Namespace string `json:"namespace,omitempty"` } // Validate validates this status OK body diff --git a/api/ha/v1beta1/json/v1beta1.json b/api/ha/v1beta1/json/v1beta1.json index c31b0b7b675..90ba0d68b29 100644 --- a/api/ha/v1beta1/json/v1beta1.json +++ b/api/ha/v1beta1/json/v1beta1.json @@ -122,6 +122,11 @@ "description": "Status of HA mode: \"Enabled\" or \"Disabled\".", "type": "string", "x-order": 0 + }, + "namespace": { + "description": "Kubernetes namespace this instance is running in. Empty if unknown\n(e.g. non-Kubernetes installs).", + "type": "string", + "x-order": 1 } } } diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index ac4a6f1a126..b83098e6186 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -5323,6 +5323,11 @@ "description": "Status of HA mode: \"Enabled\" or \"Disabled\".", "type": "string", "x-order": 0 + }, + "namespace": { + "description": "Kubernetes namespace this instance is running in. Empty if unknown\n(e.g. non-Kubernetes installs).", + "type": "string", + "x-order": 1 } } } diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index c40c51e6c46..b796a8478e8 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4350,6 +4350,11 @@ "description": "Status of HA mode: \"Enabled\" or \"Disabled\".", "type": "string", "x-order": 0 + }, + "namespace": { + "description": "Kubernetes namespace this instance is running in. Empty if unknown\n(e.g. non-Kubernetes installs).", + "type": "string", + "x-order": 1 } } } diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 2468e9778a0..6a767359dd5 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -804,6 +804,10 @@ func main() { //nolint:gocognit,maintidx,cyclop if *haPeers != "" { nodes = strings.Split(*haPeers, ",") } + var namespace string + if *haEnabled { + namespace = ha.DetectNamespace(l) + } haParams := &models.HAParams{ Enabled: *haEnabled, NodeID: *haNodeID, @@ -812,6 +816,7 @@ func main() { //nolint:gocognit,maintidx,cyclop RaftPort: *haRaftPort, GossipPort: *haGossipPort, GrafanaGossipPort: *haGrafanaGossipPort, + Namespace: namespace, } haService := ha.New(haParams) diff --git a/managed/models/params.go b/managed/models/params.go index 97fad048831..1b0ea213b6a 100644 --- a/managed/models/params.go +++ b/managed/models/params.go @@ -26,6 +26,8 @@ type HAParams struct { Nodes []string RaftPort int GossipPort int + // Namespace is the Kubernetes namespace this instance is running in, if known. + Namespace string } // Params defines parameters for supervisor. diff --git a/managed/services/ha/ha.go b/managed/services/ha/ha.go index 0a0bef81470..8f4b7992404 100644 --- a/managed/services/ha/ha.go +++ b/managed/services/ha/ha.go @@ -43,7 +43,7 @@ func (s *HAServer) Status(_ context.Context, _ *hav1beta1.StatusRequest) (*hav1b if s.service.params.Enabled { status = "Enabled" } - return &hav1beta1.StatusResponse{Status: status}, nil + return &hav1beta1.StatusResponse{Status: status, Namespace: s.service.params.Namespace}, nil } // ListNodes returns a list of all nodes in the High Availability cluster. diff --git a/managed/services/ha/haservice.go b/managed/services/ha/haservice.go index 19de9cd0184..8d5763d045c 100644 --- a/managed/services/ha/haservice.go +++ b/managed/services/ha/haservice.go @@ -58,6 +58,11 @@ const ( defaultSnapshotInterval = 120 * time.Second defaultServerOpTimeout = 10 * time.Second defaultDNSLookupTimeout = 3 * time.Second + + // serviceAccountNamespaceFile is auto-projected by Kubernetes into every pod + // that mounts a service account token (the default), same mechanism used by + // client-go's in-cluster config to detect the current namespace. + serviceAccountNamespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" ) // Service represents the high-availability service. @@ -208,6 +213,23 @@ func setupRaftStorage(nodeID string, l *logrus.Entry) (*raftboltdb.BoltStore, *r return logStore, stableStore, snapshotStore, nil } +// DetectNamespace returns the Kubernetes namespace this process is running in, +// or an empty string if it can't be determined (e.g. non-Kubernetes installs, +// or a service account without the token automounted). Missing the file is an +// expected, non-fatal condition, not an error worth surfacing to the user. +func DetectNamespace(l *logrus.Entry) string { + return detectNamespaceAt(serviceAccountNamespaceFile, l) +} + +func detectNamespaceAt(path string, l *logrus.Entry) string { + data, err := os.ReadFile(path) //nolint:gosec + if err != nil { + l.WithError(err).Debug("could not detect Kubernetes namespace") + return "" + } + return strings.TrimSpace(string(data)) +} + // New provides a new instance of the high availability service. func New(params *models.HAParams) *Service { return &Service{ diff --git a/managed/services/ha/haservice_test.go b/managed/services/ha/haservice_test.go index c49db993a41..fdf3d72a549 100644 --- a/managed/services/ha/haservice_test.go +++ b/managed/services/ha/haservice_test.go @@ -283,6 +283,38 @@ func TestService_BroadcastMessage(t *testing.T) { }) } +func TestDetectNamespaceAt(t *testing.T) { + t.Parallel() + + l := logrus.WithField("component", "test") + + t.Run("file present", func(t *testing.T) { + t.Parallel() + + path := filepath.Join(t.TempDir(), "namespace") + require.NoError(t, os.WriteFile(path, []byte("pmm-ha\n"), 0o600)) + + assert.Equal(t, "pmm-ha", detectNamespaceAt(path, l)) + }) + + t.Run("file missing", func(t *testing.T) { + t.Parallel() + + path := filepath.Join(t.TempDir(), "does-not-exist") + + assert.Empty(t, detectNamespaceAt(path, l)) + }) + + t.Run("file with surrounding whitespace", func(t *testing.T) { + t.Parallel() + + path := filepath.Join(t.TempDir(), "namespace") + require.NoError(t, os.WriteFile(path, []byte(" pmm-ha \n\n"), 0o600)) + + assert.Equal(t, "pmm-ha", detectNamespaceAt(path, l)) + }) +} + type mockSnapshotSink struct { closed bool } diff --git a/ui/apps/pmm/src/hooks/api/useHA.ts b/ui/apps/pmm/src/hooks/api/useHA.ts index 8b93c82b008..757cb928e63 100644 --- a/ui/apps/pmm/src/hooks/api/useHA.ts +++ b/ui/apps/pmm/src/hooks/api/useHA.ts @@ -50,6 +50,7 @@ export const useHaInfo = ( health, leader, nodes: nodesQuery.data?.nodes || [], + namespace: statusQuery.data?.namespace, }, isLoading: nodesQuery.isLoading || statusQuery.isLoading, }; diff --git a/ui/apps/pmm/src/types/ha.types.ts b/ui/apps/pmm/src/types/ha.types.ts index cc1d9a9d735..90af0f6c439 100644 --- a/ui/apps/pmm/src/types/ha.types.ts +++ b/ui/apps/pmm/src/types/ha.types.ts @@ -1,5 +1,6 @@ export interface GetHAStatusResponse { status: HAStatus; + namespace?: string; } export type HAStatus = 'Enabled' | 'Disabled'; @@ -28,6 +29,7 @@ export interface HAInfo { health: HAHealth; leader?: GetHANodeResponse; nodes: GetHANodeResponse[]; + namespace?: string; } export type HAHealth = From c4d200bd8608624c4a947affa69b03f9253b0dec Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Sun, 9 Aug 2026 01:11:02 +0100 Subject: [PATCH 10/10] Revert "chore: project k8s namespace into pods and UI" This reverts commit 04ba11b65b9f1af19695dfa10a71f0f799fabff7. --- api/ha/v1beta1/ha.pb.go | 18 +++-------- api/ha/v1beta1/ha.pb.validate.go | 2 -- api/ha/v1beta1/ha.proto | 3 -- .../client/ha_service/status_responses.go | 4 --- api/ha/v1beta1/json/v1beta1.json | 5 --- api/swagger/swagger-dev.json | 5 --- api/swagger/swagger.json | 5 --- managed/cmd/pmm-managed/main.go | 5 --- managed/models/params.go | 2 -- managed/services/ha/ha.go | 2 +- managed/services/ha/haservice.go | 22 ------------- managed/services/ha/haservice_test.go | 32 ------------------- ui/apps/pmm/src/hooks/api/useHA.ts | 1 - ui/apps/pmm/src/types/ha.types.ts | 2 -- 14 files changed, 5 insertions(+), 103 deletions(-) diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index a32c365477d..644ec65f4b2 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -267,10 +267,7 @@ func (*StatusRequest) Descriptor() ([]byte, []int) { type StatusResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // Status of HA mode: "Enabled" or "Disabled". - Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - // Kubernetes namespace this instance is running in. Empty if unknown - // (e.g. non-Kubernetes installs). - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -312,13 +309,6 @@ func (x *StatusResponse) GetStatus() string { return "" } -func (x *StatusResponse) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - var File_ha_v1beta1_ha_proto protoreflect.FileDescriptor const file_ha_v1beta1_ha_proto_rawDesc = "" + @@ -333,10 +323,9 @@ const file_ha_v1beta1_ha_proto_rawDesc = "" + "\x11ListNodesResponse\x12(\n" + "\x05nodes\x18\x01 \x03(\v2\x12.ha.v1beta1.HANodeR\x05nodes\x12%\n" + "\x0eexpected_nodes\x18\x02 \x01(\x05R\rexpectedNodes\"\x0f\n" + - "\rStatusRequest\"F\n" + + "\rStatusRequest\"(\n" + "\x0eStatusResponse\x12\x16\n" + - "\x06status\x18\x01 \x01(\tR\x06status\x12\x1c\n" + - "\tnamespace\x18\x02 \x01(\tR\tnamespace*S\n" + + "\x06status\x18\x01 \x01(\tR\x06status*S\n" + "\bNodeRole\x12\x19\n" + "\x15NODE_ROLE_UNSPECIFIED\x10\x00\x12\x14\n" + "\x10NODE_ROLE_LEADER\x10\x01\x12\x16\n" + @@ -372,6 +361,7 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) + var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/ha/v1beta1/ha.pb.validate.go b/api/ha/v1beta1/ha.pb.validate.go index 602aede93cc..bf1c6293767 100644 --- a/api/ha/v1beta1/ha.pb.validate.go +++ b/api/ha/v1beta1/ha.pb.validate.go @@ -505,8 +505,6 @@ func (m *StatusResponse) validate(all bool) error { // no validation rules for Status - // no validation rules for Namespace - if len(errors) > 0 { return StatusResponseMultiError(errors) } diff --git a/api/ha/v1beta1/ha.proto b/api/ha/v1beta1/ha.proto index df7c8c90052..ef1c88e8bd9 100644 --- a/api/ha/v1beta1/ha.proto +++ b/api/ha/v1beta1/ha.proto @@ -36,9 +36,6 @@ message StatusRequest {} message StatusResponse { // Status of HA mode: "Enabled" or "Disabled". string status = 1; - // Kubernetes namespace this instance is running in. Empty if unknown - // (e.g. non-Kubernetes installs). - string namespace = 2; } // HAService provides High Availability cluster status information. diff --git a/api/ha/v1beta1/json/client/ha_service/status_responses.go b/api/ha/v1beta1/json/client/ha_service/status_responses.go index 8f798f30da0..573ac666934 100644 --- a/api/ha/v1beta1/json/client/ha_service/status_responses.go +++ b/api/ha/v1beta1/json/client/ha_service/status_responses.go @@ -419,10 +419,6 @@ swagger:model StatusOKBody type StatusOKBody struct { // Status of HA mode: "Enabled" or "Disabled". Status string `json:"status,omitempty"` - - // Kubernetes namespace this instance is running in. Empty if unknown - // (e.g. non-Kubernetes installs). - Namespace string `json:"namespace,omitempty"` } // Validate validates this status OK body diff --git a/api/ha/v1beta1/json/v1beta1.json b/api/ha/v1beta1/json/v1beta1.json index 90ba0d68b29..c31b0b7b675 100644 --- a/api/ha/v1beta1/json/v1beta1.json +++ b/api/ha/v1beta1/json/v1beta1.json @@ -122,11 +122,6 @@ "description": "Status of HA mode: \"Enabled\" or \"Disabled\".", "type": "string", "x-order": 0 - }, - "namespace": { - "description": "Kubernetes namespace this instance is running in. Empty if unknown\n(e.g. non-Kubernetes installs).", - "type": "string", - "x-order": 1 } } } diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index b83098e6186..ac4a6f1a126 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -5323,11 +5323,6 @@ "description": "Status of HA mode: \"Enabled\" or \"Disabled\".", "type": "string", "x-order": 0 - }, - "namespace": { - "description": "Kubernetes namespace this instance is running in. Empty if unknown\n(e.g. non-Kubernetes installs).", - "type": "string", - "x-order": 1 } } } diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index b796a8478e8..c40c51e6c46 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -4350,11 +4350,6 @@ "description": "Status of HA mode: \"Enabled\" or \"Disabled\".", "type": "string", "x-order": 0 - }, - "namespace": { - "description": "Kubernetes namespace this instance is running in. Empty if unknown\n(e.g. non-Kubernetes installs).", - "type": "string", - "x-order": 1 } } } diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 6a767359dd5..2468e9778a0 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -804,10 +804,6 @@ func main() { //nolint:gocognit,maintidx,cyclop if *haPeers != "" { nodes = strings.Split(*haPeers, ",") } - var namespace string - if *haEnabled { - namespace = ha.DetectNamespace(l) - } haParams := &models.HAParams{ Enabled: *haEnabled, NodeID: *haNodeID, @@ -816,7 +812,6 @@ func main() { //nolint:gocognit,maintidx,cyclop RaftPort: *haRaftPort, GossipPort: *haGossipPort, GrafanaGossipPort: *haGrafanaGossipPort, - Namespace: namespace, } haService := ha.New(haParams) diff --git a/managed/models/params.go b/managed/models/params.go index 1b0ea213b6a..97fad048831 100644 --- a/managed/models/params.go +++ b/managed/models/params.go @@ -26,8 +26,6 @@ type HAParams struct { Nodes []string RaftPort int GossipPort int - // Namespace is the Kubernetes namespace this instance is running in, if known. - Namespace string } // Params defines parameters for supervisor. diff --git a/managed/services/ha/ha.go b/managed/services/ha/ha.go index 8f4b7992404..0a0bef81470 100644 --- a/managed/services/ha/ha.go +++ b/managed/services/ha/ha.go @@ -43,7 +43,7 @@ func (s *HAServer) Status(_ context.Context, _ *hav1beta1.StatusRequest) (*hav1b if s.service.params.Enabled { status = "Enabled" } - return &hav1beta1.StatusResponse{Status: status, Namespace: s.service.params.Namespace}, nil + return &hav1beta1.StatusResponse{Status: status}, nil } // ListNodes returns a list of all nodes in the High Availability cluster. diff --git a/managed/services/ha/haservice.go b/managed/services/ha/haservice.go index 8d5763d045c..19de9cd0184 100644 --- a/managed/services/ha/haservice.go +++ b/managed/services/ha/haservice.go @@ -58,11 +58,6 @@ const ( defaultSnapshotInterval = 120 * time.Second defaultServerOpTimeout = 10 * time.Second defaultDNSLookupTimeout = 3 * time.Second - - // serviceAccountNamespaceFile is auto-projected by Kubernetes into every pod - // that mounts a service account token (the default), same mechanism used by - // client-go's in-cluster config to detect the current namespace. - serviceAccountNamespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" ) // Service represents the high-availability service. @@ -213,23 +208,6 @@ func setupRaftStorage(nodeID string, l *logrus.Entry) (*raftboltdb.BoltStore, *r return logStore, stableStore, snapshotStore, nil } -// DetectNamespace returns the Kubernetes namespace this process is running in, -// or an empty string if it can't be determined (e.g. non-Kubernetes installs, -// or a service account without the token automounted). Missing the file is an -// expected, non-fatal condition, not an error worth surfacing to the user. -func DetectNamespace(l *logrus.Entry) string { - return detectNamespaceAt(serviceAccountNamespaceFile, l) -} - -func detectNamespaceAt(path string, l *logrus.Entry) string { - data, err := os.ReadFile(path) //nolint:gosec - if err != nil { - l.WithError(err).Debug("could not detect Kubernetes namespace") - return "" - } - return strings.TrimSpace(string(data)) -} - // New provides a new instance of the high availability service. func New(params *models.HAParams) *Service { return &Service{ diff --git a/managed/services/ha/haservice_test.go b/managed/services/ha/haservice_test.go index fdf3d72a549..c49db993a41 100644 --- a/managed/services/ha/haservice_test.go +++ b/managed/services/ha/haservice_test.go @@ -283,38 +283,6 @@ func TestService_BroadcastMessage(t *testing.T) { }) } -func TestDetectNamespaceAt(t *testing.T) { - t.Parallel() - - l := logrus.WithField("component", "test") - - t.Run("file present", func(t *testing.T) { - t.Parallel() - - path := filepath.Join(t.TempDir(), "namespace") - require.NoError(t, os.WriteFile(path, []byte("pmm-ha\n"), 0o600)) - - assert.Equal(t, "pmm-ha", detectNamespaceAt(path, l)) - }) - - t.Run("file missing", func(t *testing.T) { - t.Parallel() - - path := filepath.Join(t.TempDir(), "does-not-exist") - - assert.Empty(t, detectNamespaceAt(path, l)) - }) - - t.Run("file with surrounding whitespace", func(t *testing.T) { - t.Parallel() - - path := filepath.Join(t.TempDir(), "namespace") - require.NoError(t, os.WriteFile(path, []byte(" pmm-ha \n\n"), 0o600)) - - assert.Equal(t, "pmm-ha", detectNamespaceAt(path, l)) - }) -} - type mockSnapshotSink struct { closed bool } diff --git a/ui/apps/pmm/src/hooks/api/useHA.ts b/ui/apps/pmm/src/hooks/api/useHA.ts index 757cb928e63..8b93c82b008 100644 --- a/ui/apps/pmm/src/hooks/api/useHA.ts +++ b/ui/apps/pmm/src/hooks/api/useHA.ts @@ -50,7 +50,6 @@ export const useHaInfo = ( health, leader, nodes: nodesQuery.data?.nodes || [], - namespace: statusQuery.data?.namespace, }, isLoading: nodesQuery.isLoading || statusQuery.isLoading, }; diff --git a/ui/apps/pmm/src/types/ha.types.ts b/ui/apps/pmm/src/types/ha.types.ts index 90af0f6c439..cc1d9a9d735 100644 --- a/ui/apps/pmm/src/types/ha.types.ts +++ b/ui/apps/pmm/src/types/ha.types.ts @@ -1,6 +1,5 @@ export interface GetHAStatusResponse { status: HAStatus; - namespace?: string; } export type HAStatus = 'Enabled' | 'Disabled'; @@ -29,7 +28,6 @@ export interface HAInfo { health: HAHealth; leader?: GetHANodeResponse; nodes: GetHANodeResponse[]; - namespace?: string; } export type HAHealth =