diff --git a/.betterer.results b/.betterer.results index 8862d56c298..7a36a4d05bf 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2437,17 +2437,7 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], "public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.ts:5381": [ -<<<<<<< HEAD - [0, 0, 0, "Do not use any type assertions.", "0"], - [0, 0, 0, "Do not use any type assertions.", "1"] -||||||| eb8dfe7933d - [0, 0, 0, "Do not use any type assertions.", "0"], - [0, 0, 0, "Do not use any type assertions.", "1"], - [0, 0, 0, "Do not use any type assertions.", "2"], - [0, 0, 0, "Do not use any type assertions.", "3"] -======= [0, 0, 0, "Do not use any type assertions.", "0"] ->>>>>>> 6073626683dd3e9f437a533ef55fd79baaceb982 ], "public/app/features/dashboard-scene/utils/test-utils.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], diff --git a/package.json b/package.json index e600f50006a..6ba514b0104 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "@types/react": "18.2.15", "@types/react-beautiful-dnd": "13.1.8", "@types/react-dom": "18.2.7", - "@types/react-grid-layout": "1.3.2", + "@types/react-grid-layout": "1.3.5", "@types/react-highlight-words": "0.16.7", "@types/react-router-dom": "5.3.3", "@types/react-table": "7.7.19", @@ -198,15 +198,15 @@ "jest-junit": "16.0.0", "jest-matcher-utils": "29.7.0", "lerna": "7.4.1", - "mini-css-extract-plugin": "2.7.6", + "mini-css-extract-plugin": "2.7.7", "msw": "1.3.2", "mutationobserver-shim": "0.3.7", "ngtemplate-loader": "2.1.0", "node-notifier": "10.0.1", - "postcss": "8.4.31", - "postcss-loader": "7.3.3", + "postcss": "8.4.33", + "postcss-loader": "7.3.4", "postcss-reporter": "7.0.5", - "postcss-scss": "4.0.6", + "postcss-scss": "4.0.9", "prettier": "3.0.0", "react-refresh": "0.14.0", "react-select-event": "5.5.1", @@ -350,7 +350,7 @@ "ml-regression-polynomial": "^3.0.0", "ml-regression-simple-linear": "^3.0.0", "moment": "2.29.4", - "moment-timezone": "0.5.43", + "moment-timezone": "0.5.44", "monaco-editor": "0.34.0", "monaco-promql": "1.7.4", "mousetrap": "1.6.5", @@ -359,7 +359,7 @@ "nanoid": "^5.0.4", "node-forge": "^1.3.1", "ol": "7.4.0", - "ol-ext": "4.0.10", + "ol-ext": "4.0.13", "papaparse": "5.4.1", "pluralize": "^8.0.0", "prismjs": "1.29.0", @@ -369,15 +369,15 @@ "rc-drawer": "6.5.2", "rc-slider": "10.3.1", "rc-time-picker": "3.7.3", - "rc-tree": "5.8.0", - "re-resizable": "6.9.9", + "rc-tree": "5.8.2", + "re-resizable": "6.9.11", "react": "18.2.0", "react-beautiful-dnd": "13.1.1", "react-diff-viewer": "^3.1.1", "react-dom": "18.2.0", - "react-draggable": "4.4.5", + "react-draggable": "4.4.6", "react-dropzone": "^14.2.3", - "react-grid-layout": "1.4.2", + "react-grid-layout": "1.4.4", "react-highlight-words": "0.20.0", "react-hook-form": "^7.49.2", "react-i18next": "^12.0.0", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index 291f5603f19..1b78191a89f 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -49,7 +49,7 @@ "marked": "5.1.1", "marked-mangle": "1.1.6", "moment": "2.29.4", - "moment-timezone": "0.5.43", + "moment-timezone": "0.5.44", "ol": "7.4.0", "papaparse": "5.4.1", "react-use": "17.4.0", diff --git a/pkg/infra/metrics/metrics.go b/pkg/infra/metrics/metrics.go index 4ed18149f8b..a938f59aefc 100644 --- a/pkg/infra/metrics/metrics.go +++ b/pkg/infra/metrics/metrics.go @@ -128,6 +128,9 @@ var ( // MAccessPermissionsSummary is a metric summary for loading permissions request duration when evaluating access MAccessPermissionsSummary prometheus.Histogram + // MSearchPermissionsSummary is a metric summary for searching permissions request duration + MAccessSearchPermissionsSummary prometheus.Histogram + // MAccessEvaluationsSummary is a metric summary for loading permissions request duration when evaluating access MAccessEvaluationsSummary prometheus.Histogram ) @@ -581,6 +584,12 @@ func init() { Namespace: ExporterName, }) + MAccessSearchPermissionsSummary = prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "access_search_permissions_duration", + Help: "Histogram for the runtime of permissions search function", + Buckets: prometheus.ExponentialBuckets(0.001, 4, 5), + }) + StatsTotalLibraryPanels = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "stat_totals_library_panels", Help: "total amount of library panels in the database", @@ -698,6 +707,7 @@ func initMetricVars(reg prometheus.Registerer) { MRenderingQueue, MAccessPermissionsSummary, MAccessEvaluationsSummary, + MAccessSearchPermissionsSummary, MAlertingActiveAlerts, MStatTotalDashboards, MStatTotalFolders, diff --git a/pkg/services/accesscontrol/acimpl/service.go b/pkg/services/accesscontrol/acimpl/service.go index fa6471a8ca8..eb43561cdb7 100644 --- a/pkg/services/accesscontrol/acimpl/service.go +++ b/pkg/services/accesscontrol/acimpl/service.go @@ -242,6 +242,9 @@ func (s *Service) DeclarePluginRoles(ctx context.Context, ID, name string, regs // SearchUsersPermissions returns all users' permissions filtered by action prefixes func (s *Service) SearchUsersPermissions(ctx context.Context, user identity.Requester, options accesscontrol.SearchOptions) (map[int64][]accesscontrol.Permission, error) { + timer := prometheus.NewTimer(metrics.MAccessSearchPermissionsSummary) + defer timer.ObserveDuration() + // Filter ram permissions basicPermissions := map[string][]accesscontrol.Permission{} for role, basicRole := range s.roles { diff --git a/pkg/services/authn/clients/oauth.go b/pkg/services/authn/clients/oauth.go index c27a63b1d03..e0a4bc676dc 100644 --- a/pkg/services/authn/clients/oauth.go +++ b/pkg/services/authn/clients/oauth.go @@ -112,7 +112,7 @@ func (c *OAuth) Authenticate(ctx context.Context, r *authn.Request) (*authn.Iden if err != nil { return nil, errOAuthMissingPKCE.Errorf("no pkce cookie found: %w", err) } - opts = append(opts, oauth2.SetAuthURLParam(codeVerifierParamName, pkceCookie.Value)) + opts = append(opts, oauth2.VerifierOption(pkceCookie.Value)) } clientCtx := context.WithValue(ctx, oauth2.HTTPClient, c.httpClient) @@ -184,16 +184,13 @@ func (c *OAuth) RedirectURL(ctx context.Context, r *authn.Request) (*authn.Redir var plainPKCE string if c.oauthCfg.UsePKCE { - pkce, hashedPKCE, err := genPKCECode() + verifier, err := genPKCECodeVerifier() if err != nil { return nil, errOAuthGenPKCE.Errorf("failed to generate pkce: %w", err) } - plainPKCE = pkce - opts = append(opts, - oauth2.SetAuthURLParam(codeChallengeParamName, hashedPKCE), - oauth2.SetAuthURLParam(codeChallengeMethodParamName, codeChallengeMethod), - ) + plainPKCE = verifier + opts = append(opts, oauth2.S256ChallengeOption(plainPKCE)) } state, hashedSate, err := genOAuthState(c.cfg.SecretKey, c.oauthCfg.ClientSecret) @@ -233,8 +230,8 @@ func (c *OAuth) Logout(ctx context.Context, user identity.Requester, info *login return &authn.Redirect{URL: redirctURL}, true } -// genPKCECode returns a random URL-friendly string and it's base64 URL encoded SHA256 digest. -func genPKCECode() (string, string, error) { +// genPKCECodeVerifier returns code verifier that 128 characters random URL-friendly string. +func genPKCECodeVerifier() (string, error) { // IETF RFC 7636 specifies that the code verifier should be 43-128 // characters from a set of unreserved URI characters which is // almost the same as the set of characters in base64url. @@ -249,14 +246,12 @@ func genPKCECode() (string, string, error) { raw := make([]byte, 96) _, err := rand.Read(raw) if err != nil { - return "", "", err + return "", err } ascii := make([]byte, 128) base64.RawURLEncoding.Encode(ascii, raw) - shasum := sha256.Sum256(ascii) - pkce := base64.RawURLEncoding.EncodeToString(shasum[:]) - return string(ascii), pkce, nil + return string(ascii), nil } func genOAuthState(secret, seed string) (string, string, error) { diff --git a/pkg/services/authn/clients/oauth_test.go b/pkg/services/authn/clients/oauth_test.go index 893bc6934f9..b9d5cf57e0c 100644 --- a/pkg/services/authn/clients/oauth_test.go +++ b/pkg/services/authn/clients/oauth_test.go @@ -268,7 +268,7 @@ func TestOAuth_RedirectURL(t *testing.T) { { desc: "should generate redirect url with pkce if configured", oauthCfg: &social.OAuthInfo{UsePKCE: true}, - numCallOptions: 2, + numCallOptions: 1, authCodeUrlCalled: true, }, } @@ -404,6 +404,12 @@ func TestOAuth_Logout(t *testing.T) { } } +func TestGenPKCECodeVerifier(t *testing.T) { + verifier, err := genPKCECodeVerifier() + assert.NoError(t, err) + assert.Len(t, verifier, 128) +} + type mockConnector struct { AuthCodeURLFunc func(state string, opts ...oauth2.AuthCodeOption) string social.SocialConnector diff --git a/pkg/tsdb/cloudwatch/time_series_query.go b/pkg/tsdb/cloudwatch/time_series_query.go index a228f571211..28d5f558e62 100644 --- a/pkg/tsdb/cloudwatch/time_series_query.go +++ b/pkg/tsdb/cloudwatch/time_series_query.go @@ -3,6 +3,7 @@ package cloudwatch import ( "context" "fmt" + "regexp" "github.com/grafana/grafana-plugin-sdk-go/backend" "golang.org/x/sync/errgroup" @@ -121,6 +122,7 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger Error: fmt.Errorf("metric request error: %q", err), } resultChan <- &responseWrapper{ + RefId: getQueryRefIdFromErrorString(err.Error(), requestQueries), DataResponse: &dataResponse, } } @@ -132,3 +134,17 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, logger return resp, nil } + +func getQueryRefIdFromErrorString(err string, queries []*models.CloudWatchQuery) string { + // error can be in format "Error in expression 'test': Invalid syntax" + // so we can find the query id or ref id between the quotations + erroredRefId := "" + + for _, query := range queries { + if regexp.MustCompile(`'`+query.RefId+`':`).MatchString(err) || regexp.MustCompile(`'`+query.Id+`':`).MatchString(err) { + erroredRefId = query.RefId + } + } + // if errorRefId is empty, it means the error concerns all queries (error metric limit exceeded, for example) + return erroredRefId +} diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx index 4e9e9cf5948..d78a2087c4c 100644 --- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx @@ -16,12 +16,7 @@ export interface ContactPointSelectorProps { } export function ContactPointSelector({ alertManager, contactPoints, onSelectContactPoint }: ContactPointSelectorProps) { const styles = useStyles2(getStyles); - const { - register, - control, - formState: { errors }, - watch, - } = useFormContext(); + const { control, watch } = useFormContext(); const options = contactPoints.map((receiver) => { const integrations = receiver?.grafana_managed_receiver_configs; @@ -39,11 +34,7 @@ export function ContactPointSelector({ alertManager, contactPoints, onSelectCont return ( - + ( <> @@ -65,9 +56,10 @@ export function ContactPointSelector({ alertManager, contactPoints, onSelectCont width={50} /> - {error && {'Contact point is required.'}} + {error && {error.message}} )} + rules={{ required: { value: true, message: 'Contact point is required.' } }} control={control} name={`contactPoints.${alertManager}.selectedContactPoint`} /> diff --git a/public/app/plugins/datasource/cloudwatch/__mocks__/MetricsQueryRunner.ts b/public/app/plugins/datasource/cloudwatch/__mocks__/MetricsQueryRunner.ts index 5025d723d49..ace86da0ec5 100644 --- a/public/app/plugins/datasource/cloudwatch/__mocks__/MetricsQueryRunner.ts +++ b/public/app/plugins/datasource/cloudwatch/__mocks__/MetricsQueryRunner.ts @@ -1,7 +1,6 @@ -import { of, throwError } from 'rxjs'; +import { of } from 'rxjs'; -import { CustomVariableModel, DataQueryError, DataQueryRequest, DataSourceInstanceSettings } from '@grafana/data'; -import { BackendDataSourceResponse, toDataQueryResponse } from '@grafana/runtime'; +import { CustomVariableModel, DataQueryRequest, DataQueryResponse, DataSourceInstanceSettings } from '@grafana/data'; import { CloudWatchMetricsQueryRunner } from '../query-runner/CloudWatchMetricsQueryRunner'; import { CloudWatchJsonData, CloudWatchQuery } from '../types'; @@ -10,23 +9,17 @@ import { CloudWatchSettings, setupMockedTemplateService } from './CloudWatchData import { TimeRangeMock } from './timeRange'; export function setupMockedMetricsQueryRunner({ - data = { - results: {}, - }, + response = { data: [] }, variables, - errorResponse, instanceSettings = CloudWatchSettings, }: { - data?: BackendDataSourceResponse; + response?: DataQueryResponse; variables?: CustomVariableModel[]; - errorResponse?: DataQueryError; instanceSettings?: DataSourceInstanceSettings; } = {}) { const templateService = setupMockedTemplateService(variables); - const queryMock = errorResponse - ? jest.fn().mockImplementation(() => throwError(errorResponse)) - : jest.fn().mockReturnValue(of(toDataQueryResponse({ data }))); + const queryMock = jest.fn().mockImplementation(() => of(response)); const runner = new CloudWatchMetricsQueryRunner(instanceSettings, templateService); const request: DataQueryRequest = { diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx index 619621253b6..56d613dd8cd 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx @@ -3,8 +3,8 @@ import React from 'react'; import { GrafanaTheme2, DataSourceInstanceSettings } from '@grafana/data'; import { ConfigSection } from '@grafana/experimental'; +import { DataSourcePicker } from '@grafana/runtime'; import { Alert, Field, InlineField, useStyles2 } from '@grafana/ui'; -import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; const getStyles = (theme: GrafanaTheme2) => ({ diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts index 0da562839c5..2c9ecfa31de 100644 --- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts +++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts @@ -2,7 +2,7 @@ import { of } from 'rxjs'; import { CustomVariableModel, getFrameDisplayName, VariableHide } from '@grafana/data'; import { dateTime } from '@grafana/data/src/datetime/moment_wrapper'; -import { BackendDataSourceResponse } from '@grafana/runtime'; +import { toDataQueryResponse } from '@grafana/runtime'; import * as redux from 'app/store/store'; import { @@ -17,18 +17,28 @@ import { import { initialVariableModelState } from '../__mocks__/CloudWatchVariables'; import { setupMockedMetricsQueryRunner } from '../__mocks__/MetricsQueryRunner'; import { validMetricSearchBuilderQuery, validMetricSearchCodeQuery } from '../__mocks__/queries'; -import { MetricQueryType, MetricEditorMode, CloudWatchMetricsQuery, DataQueryError } from '../types'; +import { MetricQueryType, MetricEditorMode, CloudWatchMetricsQuery } from '../types'; describe('CloudWatchMetricsQueryRunner', () => { describe('performTimeSeriesQuery', () => { it('should return the same length of data as result', async () => { - const { runner, timeRange, request, queryMock } = setupMockedMetricsQueryRunner({ + const resultsFromBEQuery = { data: { results: { - a: { refId: 'a', series: [{ target: 'cpu', datapoints: [[1, 1]] }] }, - b: { refId: 'b', series: [{ target: 'memory', datapoints: [[2, 2]] }] }, + a: { + refId: 'a', + series: [{ target: 'cpu', datapoints: [[1, 2]], meta: { custom: { period: 60 } } }], + }, + b: { + refId: 'b', + series: [{ target: 'cpu', datapoints: [[1, 2]], meta: { custom: { period: 120 } } }], + }, }, }, + }; + const { runner, timeRange, request, queryMock } = setupMockedMetricsQueryRunner({ + // DataSourceWithBackend runs toDataQueryResponse({response from CW backend}) + response: toDataQueryResponse(resultsFromBEQuery), }); const observable = runner.performTimeSeriesQuery( @@ -47,7 +57,7 @@ describe('CloudWatchMetricsQueryRunner', () => { }); it('sets fields.config.interval based on period', async () => { - const { runner, timeRange, request, queryMock } = setupMockedMetricsQueryRunner({ + const resultsFromBEQuery = { data: { results: { a: { @@ -60,6 +70,10 @@ describe('CloudWatchMetricsQueryRunner', () => { }, }, }, + }; + const { runner, timeRange, request, queryMock } = setupMockedMetricsQueryRunner({ + // DataSourceWithBackend runs toDataQueryResponse({response from CW backend}) + response: toDataQueryResponse(resultsFromBEQuery), }); const observable = runner.performTimeSeriesQuery( @@ -98,31 +112,36 @@ describe('CloudWatchMetricsQueryRunner', () => { }, ]; - const data: BackendDataSourceResponse = { - results: { - A: { - tables: [], - error: '', - refId: 'A', - series: [ - { - target: 'CPUUtilization_Average', - datapoints: [ - [1, 1483228800000], - [2, 1483229100000], - [5, 1483229700000], - ], - tags: { - InstanceId: 'i-12345678', + const resultsFromBEQuery = { + data: { + results: { + A: { + tables: [], + error: '', + refId: 'A', + series: [ + { + target: 'CPUUtilization_Average', + datapoints: [ + [1, 1483228800000], + [2, 1483229100000], + [5, 1483229700000], + ], + tags: { + InstanceId: 'i-12345678', + }, }, - }, - ], + ], + }, }, }, }; it('should generate the correct query', async () => { - const { runner, queryMock, request } = setupMockedMetricsQueryRunner({ data }); + const { runner, queryMock, request } = setupMockedMetricsQueryRunner({ + // DataSourceWithBackend runs toDataQueryResponse({response from CW backend}) + response: toDataQueryResponse(resultsFromBEQuery), + }); await expect(runner.handleMetricQueries(queries, request, queryMock)).toEmitValuesWith(() => { expect(queryMock.mock.calls[0][0].targets).toMatchObject( @@ -159,7 +178,8 @@ describe('CloudWatchMetricsQueryRunner', () => { ]; const { runner, queryMock, request } = setupMockedMetricsQueryRunner({ - data, + // DataSourceWithBackend runs toDataQueryResponse({response from CW backend}) + response: toDataQueryResponse(resultsFromBEQuery), variables: [periodIntervalVariable], }); @@ -169,110 +189,111 @@ describe('CloudWatchMetricsQueryRunner', () => { }); it('should return series list', async () => { - const { runner, request, queryMock } = setupMockedMetricsQueryRunner({ data }); + const { runner, request, queryMock } = setupMockedMetricsQueryRunner({ + // DataSourceWithBackend runs toDataQueryResponse({response from CW backend}) + response: toDataQueryResponse(resultsFromBEQuery), + }); await expect(runner.handleMetricQueries(queries, request, queryMock)).toEmitValuesWith((received) => { const result = received[0]; - expect(getFrameDisplayName(result.data[0])).toBe( - data.results.A.series?.length && data.results.A.series[0].target - ); - expect(result.data[0].fields[1].values[0]).toBe( - data.results.A.series?.length && data.results.A.series[0].datapoints[0][0] - ); + expect(getFrameDisplayName(result.data[0])).toBe('CPUUtilization_Average'); + expect(result.data[0].fields[1].values[0]).toBe(1); + }); + }); + }); + describe('and throttling exception is thrown', () => { + const partialQuery: CloudWatchMetricsQuery = { + metricQueryType: MetricQueryType.Search, + metricEditorMode: MetricEditorMode.Builder, + queryMode: 'Metrics', + namespace: 'AWS/EC2', + metricName: 'CPUUtilization', + dimensions: { + InstanceId: 'i-12345678', + }, + statistic: 'Average', + period: '300', + expression: '', + id: '', + region: '', + refId: '', + }; + + const queries: CloudWatchMetricsQuery[] = [ + { ...partialQuery, refId: 'A', region: 'us-east-1' }, + { ...partialQuery, refId: 'B', region: 'us-east-2' }, + { ...partialQuery, refId: 'C', region: 'us-east-1' }, + { ...partialQuery, refId: 'D', region: 'us-east-2' }, + { ...partialQuery, refId: 'E', region: 'eu-north-1' }, + ]; + + const dataWithThrottlingError = { + data: { + message: 'Throttling: exception', + results: { + A: { + frames: [], + series: [], + tables: [], + error: 'Throttling: exception', + refId: 'A', + meta: {}, + }, + B: { + frames: [], + series: [], + tables: [], + error: 'Throttling: exception', + refId: 'B', + meta: {}, + }, + C: { + frames: [], + series: [], + tables: [], + error: 'Throttling: exception', + refId: 'C', + meta: {}, + }, + D: { + frames: [], + series: [], + tables: [], + error: 'Throttling: exception', + refId: 'D', + meta: {}, + }, + E: { + frames: [], + series: [], + tables: [], + error: 'Throttling: exception', + refId: 'E', + meta: {}, + }, + }, + }, + }; + + beforeEach(() => { + redux.setStore({ + ...redux.store, + dispatch: jest.fn(), }); }); - describe('and throttling exception is thrown', () => { - const partialQuery: CloudWatchMetricsQuery = { - metricQueryType: MetricQueryType.Search, - metricEditorMode: MetricEditorMode.Builder, - queryMode: 'Metrics', - namespace: 'AWS/EC2', - metricName: 'CPUUtilization', - dimensions: { - InstanceId: 'i-12345678', - }, - statistic: 'Average', - period: '300', - expression: '', - id: '', - region: '', - refId: '', - }; - - const queries: CloudWatchMetricsQuery[] = [ - { ...partialQuery, refId: 'A', region: 'us-east-1' }, - { ...partialQuery, refId: 'B', region: 'us-east-2' }, - { ...partialQuery, refId: 'C', region: 'us-east-1' }, - { ...partialQuery, refId: 'D', region: 'us-east-2' }, - { ...partialQuery, refId: 'E', region: 'eu-north-1' }, - ]; - - const backendErrorResponse: DataQueryError = { - data: { - message: 'Throttling: exception', - results: { - A: { - frames: [], - series: [], - tables: [], - error: 'Throttling: exception', - refId: 'A', - meta: {}, - }, - B: { - frames: [], - series: [], - tables: [], - error: 'Throttling: exception', - refId: 'B', - meta: {}, - }, - C: { - frames: [], - series: [], - tables: [], - error: 'Throttling: exception', - refId: 'C', - meta: {}, - }, - D: { - frames: [], - series: [], - tables: [], - error: 'Throttling: exception', - refId: 'D', - meta: {}, - }, - E: { - frames: [], - series: [], - tables: [], - error: 'Throttling: exception', - refId: 'E', - meta: {}, - }, - }, - }, - }; - - beforeEach(() => { - redux.setStore({ - ...redux.store, - dispatch: jest.fn(), - }); + it('should display one alert error message per region+datasource combination', async () => { + const { runner, request, queryMock } = setupMockedMetricsQueryRunner({ + response: toDataQueryResponse(dataWithThrottlingError), }); + const memoizedDebounceSpy = jest.spyOn(runner, 'debouncedThrottlingAlert'); - it('should display one alert error message per region+datasource combination', async () => { - const { runner, request, queryMock } = setupMockedMetricsQueryRunner({ errorResponse: backendErrorResponse }); - const memoizedDebounceSpy = jest.spyOn(runner, 'debouncedAlert'); - - await expect(runner.handleMetricQueries(queries, request, queryMock)).toEmitValuesWith(() => { - expect(memoizedDebounceSpy).toHaveBeenCalledWith('CloudWatch Test Datasource', 'us-east-1'); - expect(memoizedDebounceSpy).toHaveBeenCalledWith('CloudWatch Test Datasource', 'us-east-2'); - expect(memoizedDebounceSpy).toHaveBeenCalledWith('CloudWatch Test Datasource', 'eu-north-1'); - expect(memoizedDebounceSpy).toBeCalledTimes(3); - }); + await expect(runner.handleMetricQueries(queries, request, queryMock)).toEmitValuesWith((received) => { + expect(received[0].errors).toHaveLength(5); + expect(memoizedDebounceSpy).toHaveBeenCalledWith('CloudWatch Test Datasource', 'us-east-1'); + expect(memoizedDebounceSpy).toHaveBeenCalledWith('CloudWatch Test Datasource', 'us-east-2'); + expect(memoizedDebounceSpy).toHaveBeenCalledWith('CloudWatch Test Datasource', 'eu-north-1'); + expect(memoizedDebounceSpy).toBeCalledTimes(3); }); }); }); @@ -298,43 +319,80 @@ describe('CloudWatchMetricsQueryRunner', () => { }, ]; - const data: BackendDataSourceResponse = { - results: { - A: { - tables: [], - error: '', - refId: 'A', - series: [ - { - target: 'TargetResponseTime_p90.00', - datapoints: [ - [1, 1483228800000], - [2, 1483229100000], - [5, 1483229700000], - ], - tags: { - LoadBalancer: 'lb', - TargetGroup: 'tg', + const responseFromBEQuery = { + data: { + results: { + A: { + tables: [], + error: '', + refId: 'A', + series: [ + { + target: 'TargetResponseTime_p90.00', + datapoints: [ + [1, 1483228800000], + [2, 1483229100000], + [5, 1483229700000], + ], + tags: { + LoadBalancer: 'lb', + TargetGroup: 'tg', + }, }, - }, - ], + ], + }, }, }, }; it('should return series list', async () => { - const { runner, request, queryMock } = setupMockedMetricsQueryRunner({ data }); + const { runner, request, queryMock } = setupMockedMetricsQueryRunner({ + // DataSourceWithBackend runs toDataQueryResponse({response from CW backend}) + response: toDataQueryResponse(responseFromBEQuery), + }); await expect(runner.handleMetricQueries(queries, request, queryMock)).toEmitValuesWith((received) => { const result = received[0]; expect(getFrameDisplayName(result.data[0])).toBe( - data.results.A.series?.length && data.results.A.series[0].target + responseFromBEQuery.data.results.A.series?.length && responseFromBEQuery.data.results.A.series[0].target ); expect(result.data[0].fields[1].values[0]).toBe( - data.results.A.series?.length && data.results.A.series[0].datapoints[0][0] + responseFromBEQuery.data.results.A.series?.length && + responseFromBEQuery.data.results.A.series[0].datapoints[0][0] ); }); }); + it('should pass the error list from DatasourceWithBackend srv', async () => { + const dataWithError = { + data: { + results: { + A: { + error: + "metric request error: \"ValidationError: Error in expression 'query': Invalid syntax\\n\\tstatus code: 400", + status: 500, + }, + }, + }, + status: 500, + statusText: 'Internal Server Error', + }; + const { runner, request, queryMock } = setupMockedMetricsQueryRunner({ + // DataSourceWithBackend runs toDataQueryResponse({response from CW backend}) + response: toDataQueryResponse(dataWithError), + }); + await expect(runner.handleMetricQueries(queries, request, queryMock)).toEmitValuesWith((received) => { + const result = received[0]; + expect(result.data).toEqual([]); + expect(result.errors).toEqual([ + { + message: + "metric request error: \"ValidationError: Error in expression 'query': Invalid syntax\\n\\tstatus code: 400", + status: 500, + refId: 'A', + }, + ]); + }); + }); }); describe('template variable interpolation', () => { diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts index 58cea66694e..b0d36396628 100644 --- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts +++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts @@ -1,9 +1,10 @@ -import { findLast, isEmpty } from 'lodash'; +import { isEmpty } from 'lodash'; import React from 'react'; -import { catchError, map, Observable, of, throwError } from 'rxjs'; +import { catchError, map, Observable, of } from 'rxjs'; import { DataFrame, + DataQueryError, DataQueryRequest, DataQueryResponse, DataSourceInstanceSettings, @@ -21,7 +22,7 @@ import { AppNotificationTimeout } from 'app/types'; import { ThrottlingErrorMessage } from '../components/Errors/ThrottlingErrorMessage'; import memoizedDebounce from '../memoizedDebounce'; import { migrateMetricQuery } from '../migrations/metricQueryMigrations'; -import { CloudWatchJsonData, CloudWatchMetricsQuery, CloudWatchQuery, DataQueryError } from '../types'; +import { CloudWatchJsonData, CloudWatchMetricsQuery, CloudWatchQuery } from '../types'; import { filterMetricsQuery } from '../utils/utils'; import { CloudWatchRequest } from './CloudWatchRequest'; @@ -37,9 +38,10 @@ const displayAlert = (datasourceName: string, region: string) => ) ) ); + // This class handles execution of CloudWatch metrics query data queries export class CloudWatchMetricsQueryRunner extends CloudWatchRequest { - debouncedAlert: (datasourceName: string, region: string) => void = memoizedDebounce( + debouncedThrottlingAlert: (datasourceName: string, region: string) => void = memoizedDebounce( displayAlert, AppNotificationTimeout.Error ); @@ -109,12 +111,7 @@ export class CloudWatchMetricsQueryRunner extends CloudWatchRequest { ): Observable { return queryFn(request).pipe( map((res) => { - const dataframes: DataFrame[] = res.data; - if (!dataframes || dataframes.length <= 0) { - return { data: [] }; - } - - const lastError = findLast(res.data, (v) => !!v.error); + const dataframes: DataFrame[] = res.data || []; dataframes.forEach((frame) => { frame.fields.forEach((field) => { @@ -125,47 +122,48 @@ export class CloudWatchMetricsQueryRunner extends CloudWatchRequest { }); }); + if (res.errors?.length) { + this.alertOnErrors(res.errors, request); + } + return { data: dataframes, - error: lastError ? { message: lastError.error } : undefined, + // DataSourceWithBackend will not throw an error, instead it will return "errors" field along with the response + errors: res.errors, }; }), - catchError((err: DataQueryError) => { - const isFrameError = err.data?.results; - - // Error is not frame specific - if (!isFrameError && err.data && err.data.message === 'Metric request error' && err.data.error) { - err.message = err.data.error; - return throwError(() => err); + catchError((err: unknown) => { + if (Array.isArray(err)) { + return of({ data: [], errors: err }); + } else { + return of({ data: [], errors: [{ message: err }] }); } - - // The error is either for a specific frame or for all the frames - const results: Array<{ error?: string }> = Object.values(err.data?.results ?? {}); - const firstErrorResult = results.find((r) => r.error); - if (firstErrorResult) { - err.message = firstErrorResult.error; - } - - if (results.some((r) => r.error && /^Throttling:.*/.test(r.error))) { - const failedRedIds = Object.keys(err.data?.results ?? {}); - const regionsAffected = Object.values(request.targets).reduce( - (res: string[], { refId, region }) => - (refId && !failedRedIds.includes(refId)) || res.includes(region) ? res : [...res, region], - [] - ); - regionsAffected.forEach((region) => { - const actualRegion = this.getActualRegion(region); - if (actualRegion) { - this.debouncedAlert(this.instanceSettings.name, actualRegion); - } - }); - } - - return throwError(() => err); }) ); } + alertOnErrors(errors: DataQueryError[], request: DataQueryRequest) { + const hasThrottlingError = errors.some( + (err) => err.message && (/^Throttling:.*/.test(err.message) || /^Rate exceeded.*/.test(err.message)) + ); + if (hasThrottlingError) { + const failedRefIds = errors.map((error) => error.refId).filter((refId) => refId); + if (failedRefIds.length > 0) { + const regionsAffected = Object.values(request.targets).reduce( + (res: string[], { refId, region }) => + (refId && !failedRefIds.includes(refId)) || res.includes(region) ? res : [...res, region], + [] + ); + regionsAffected.forEach((region) => { + const actualRegion = this.getActualRegion(region); + if (actualRegion) { + this.debouncedThrottlingAlert(this.instanceSettings.name, actualRegion); + } + }); + } + } + } + filterMetricQuery(query: CloudWatchMetricsQuery): boolean { return filterMetricsQuery(query); } diff --git a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx index 6fc9e91593d..b43d0363169 100644 --- a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx +++ b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx @@ -5,23 +5,15 @@ import React, { useCallback, useMemo } from 'react'; import { useAsync } from 'react-use'; import { DataQuery, GrafanaTheme2, SelectableValue, DataTopic, QueryEditorProps } from '@grafana/data'; -import { - Card, - Field, - Select, - useStyles2, - VerticalGroup, - HorizontalGroup, - Spinner, - Switch, - RadioButtonGroup, -} from '@grafana/ui'; +import { Field, Select, useStyles2, Spinner, RadioButtonGroup, Stack, InlineSwitch } from '@grafana/ui'; import config from 'app/core/config'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { PanelModel } from 'app/features/dashboard/state'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { filterPanelDataToQuery } from 'app/features/query/components/QueryEditorRow'; +import { OperationsEditorRow } from '../prometheus/querybuilder/shared/OperationsEditorRow'; + import { DashboardDatasource } from './datasource'; import { DashboardQuery, ResultInfo, SHARED_DASHBOARD_QUERY } from './types'; @@ -150,64 +142,61 @@ export function DashboardQueryEditor({ data, query, onChange, onRunQuery }: Prop const selected = panels.find((panel) => panel.value === query.panelId); return ( - <> - - onPanelChanged(item.value!)} + /> - )} - - {loadingResults ? ( - - ) : ( - <> - {results && Boolean(results.length) && ( - - - {results.map((target, i) => ( - - {target.refId} - - {target.name} - - {target.query} - - ))} - + + + + + {showTransforms && ( + + )} - - )} - + + + {loadingResults ? ( + + ) : ( + <> + {results && Boolean(results.length) && ( + + + {results.map((target, i) => ( + +
{target.refId}
+ {target.name} +
{target.query}
+
+ ))} +
+
+ )} + + )} + + ); } function getStyles(theme: GrafanaTheme2) { return { - horizontalField: css({ - marginRight: theme.spacing(2), - }), noQueriesText: css({ padding: theme.spacing(1.25), }), diff --git a/yarn.lock b/yarn.lock index af9ca874e97..5c88a321130 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3110,7 +3110,7 @@ __metadata: marked: "npm:5.1.1" marked-mangle: "npm:1.1.6" moment: "npm:2.29.4" - moment-timezone: "npm:0.5.43" + moment-timezone: "npm:0.5.44" ol: "npm:7.4.0" papaparse: "npm:5.4.1" react: "npm:18.2.0" @@ -9024,12 +9024,12 @@ __metadata: languageName: node linkType: hard -"@types/react-grid-layout@npm:1.3.2": - version: 1.3.2 - resolution: "@types/react-grid-layout@npm:1.3.2" +"@types/react-grid-layout@npm:1.3.5": + version: 1.3.5 + resolution: "@types/react-grid-layout@npm:1.3.5" dependencies: "@types/react": "npm:*" - checksum: a21fe7f790d8bd2ae385829e5d5c369788c2facfc0a9f888dc1f07b4982398e02d1ffc8fca902cd77495094a598e0951e5c907edeb773abd1bf8a6db293d54a1 + checksum: 21599054dfa977ed8445b1ab3198a842531cb36bd620564c3f8a469688cbea051149eb644a99b2f8f6d02f8d9909a6145668f385781b5647601e9663de216946 languageName: node linkType: hard @@ -12832,15 +12832,20 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:^8.2.0": - version: 8.2.0 - resolution: "cosmiconfig@npm:8.2.0" +"cosmiconfig@npm:^8.2.0, cosmiconfig@npm:^8.3.5": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" dependencies: - import-fresh: "npm:^3.2.1" + import-fresh: "npm:^3.3.0" js-yaml: "npm:^4.1.0" - parse-json: "npm:^5.0.0" + parse-json: "npm:^5.2.0" path-type: "npm:^4.0.0" - checksum: e0b188f9a672ee7135851bf9d9fc8f0ba00f9769c95fda5af0ebc274804f6aeb713b753e04e706f595e1fbd0fa67c5073840666019068c0296a06057560ab39d + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 91d082baca0f33b1c085bf010f9ded4af43cbedacba8821da0fb5667184d0a848addc52c31fadd080007f904a555319c238cf5f4c03e6d58ece2e4876b2e73d6 languageName: node linkType: hard @@ -17108,7 +17113,7 @@ __metadata: "@types/react": "npm:18.2.15" "@types/react-beautiful-dnd": "npm:13.1.8" "@types/react-dom": "npm:18.2.7" - "@types/react-grid-layout": "npm:1.3.2" + "@types/react-grid-layout": "npm:1.3.5" "@types/react-highlight-words": "npm:0.16.7" "@types/react-resizable": "npm:3.0.7" "@types/react-router-dom": "npm:5.3.3" @@ -17232,11 +17237,11 @@ __metadata: marked: "npm:5.1.1" marked-mangle: "npm:1.1.6" memoize-one: "npm:6.0.0" - mini-css-extract-plugin: "npm:2.7.6" + mini-css-extract-plugin: "npm:2.7.7" ml-regression-polynomial: "npm:^3.0.0" ml-regression-simple-linear: "npm:^3.0.0" moment: "npm:2.29.4" - moment-timezone: "npm:0.5.43" + moment-timezone: "npm:0.5.44" monaco-editor: "npm:0.34.0" monaco-promql: "npm:1.7.4" mousetrap: "npm:1.6.5" @@ -17249,13 +17254,13 @@ __metadata: node-forge: "npm:^1.3.1" node-notifier: "npm:10.0.1" ol: "npm:7.4.0" - ol-ext: "npm:4.0.10" + ol-ext: "npm:4.0.13" papaparse: "npm:5.4.1" pluralize: "npm:^8.0.0" - postcss: "npm:8.4.31" - postcss-loader: "npm:7.3.3" + postcss: "npm:8.4.33" + postcss-loader: "npm:7.3.4" postcss-reporter: "npm:7.0.5" - postcss-scss: "npm:4.0.6" + postcss-scss: "npm:4.0.9" prettier: "npm:3.0.0" prismjs: "npm:1.29.0" prop-types: "npm:15.8.1" @@ -17264,15 +17269,15 @@ __metadata: rc-drawer: "npm:6.5.2" rc-slider: "npm:10.3.1" rc-time-picker: "npm:3.7.3" - rc-tree: "npm:5.8.0" - re-resizable: "npm:6.9.9" + rc-tree: "npm:5.8.2" + re-resizable: "npm:6.9.11" react: "npm:18.2.0" react-beautiful-dnd: "npm:13.1.1" react-diff-viewer: "npm:^3.1.1" react-dom: "npm:18.2.0" - react-draggable: "npm:4.4.5" + react-draggable: "npm:4.4.6" react-dropzone: "npm:^14.2.3" - react-grid-layout: "npm:1.4.2" + react-grid-layout: "npm:1.4.4" react-highlight-words: "npm:0.20.0" react-hook-form: "npm:^7.49.2" react-i18next: "npm:^12.0.0" @@ -18177,7 +18182,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -19786,12 +19791,12 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^1.18.2": - version: 1.19.1 - resolution: "jiti@npm:1.19.1" +"jiti@npm:^1.20.0": + version: 1.21.0 + resolution: "jiti@npm:1.21.0" bin: jiti: bin/jiti.js - checksum: 88f11b406a877db348b956eb9cecf42d6cb6edcd6317aa75c032130fc88c1150baf8def5511e808af10b11336db2639a295ffe1ed455d65216dcef45a0a424b5 + checksum: 005a0239e50381b5c9919f59dbab86128367bd64872f3376dbbde54b6523f41bd134bf22909e2a509e38fd87e1c22125ca255b9b6b53e7df0fedd23f737334cc languageName: node linkType: hard @@ -21269,14 +21274,14 @@ __metadata: languageName: node linkType: hard -"mini-css-extract-plugin@npm:2.7.6": - version: 2.7.6 - resolution: "mini-css-extract-plugin@npm:2.7.6" +"mini-css-extract-plugin@npm:2.7.7": + version: 2.7.7 + resolution: "mini-css-extract-plugin@npm:2.7.7" dependencies: schema-utils: "npm:^4.0.0" peerDependencies: webpack: ^5.0.0 - checksum: 1f718bfdcb7c2bf5e4336f694e5576432149d63f9dacaf94eae38ad046534050471a712a2d1bedf95e1722a2d3b56c3361d7352849e802e4875e716885e952c3 + checksum: 55e9cb89a648e9d493dd66eb54cbf02783c6623d0e332ddb4c2374891fcd8de051d5f97473e40478eb2e091ea32fc9ac84c3cd583b445df9f444cc6b7483e1b1 languageName: node linkType: hard @@ -21633,12 +21638,12 @@ __metadata: languageName: node linkType: hard -"moment-timezone@npm:0.5.43": - version: 0.5.43 - resolution: "moment-timezone@npm:0.5.43" +"moment-timezone@npm:0.5.44": + version: 0.5.44 + resolution: "moment-timezone@npm:0.5.44" dependencies: moment: "npm:^2.29.4" - checksum: f8b66f8562960d6c2ec90ea7e2ca8c10bd5f5cf5ced2eaaac83deb1011b145d0154e8d77018cf5e913d489898a343122a3d815768809653ab039306dce1db1eb + checksum: 72f0a425c52a858cca76d5ab35dfb02d68ac7292b60e4b34fb432c1fae07e32ad7f67de7ff5d2d2c868eee8052c9981fc3244f5fc9a2f454fc4fd15db2ec45a7 languageName: node linkType: hard @@ -21850,12 +21855,12 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.6": - version: 3.3.6 - resolution: "nanoid@npm:3.3.6" +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" bin: nanoid: bin/nanoid.cjs - checksum: 67235c39d1bc05851383dadde5cf77ae1c90c2a1d189e845c7f20f646f0488d875ad5f5226bbba072a88cebbb085a3f784a6673117daf785bdf614a852550362 + checksum: ac1eb60f615b272bccb0e2b9cd933720dad30bf9708424f691b8113826bb91aca7e9d14ef5d9415a6ba15c266b37817256f58d8ce980c82b0ba3185352565679 languageName: node linkType: hard @@ -22510,12 +22515,12 @@ __metadata: languageName: node linkType: hard -"ol-ext@npm:4.0.10": - version: 4.0.10 - resolution: "ol-ext@npm:4.0.10" +"ol-ext@npm:4.0.13": + version: 4.0.13 + resolution: "ol-ext@npm:4.0.13" peerDependencies: ol: ">= 5.3.0" - checksum: 11a799c71ef53a75a7aea6bfbe43384ae4ffe1b9d5f4dac950213da165f72e33555a10f2929a6197bf49eeb25d4721a67e4798fdcbf5da519d7ad9bedae770ee + checksum: 656eea9d354296406a48590a69246433a6ae0233f2b28d77f0a6f954a53bf4b54d42a54ff50a0395b382044e7ef912f58687e0538e79a9ff0cfe2f22adf0f718 languageName: node linkType: hard @@ -23365,17 +23370,17 @@ __metadata: languageName: node linkType: hard -"postcss-loader@npm:7.3.3": - version: 7.3.3 - resolution: "postcss-loader@npm:7.3.3" +"postcss-loader@npm:7.3.4": + version: 7.3.4 + resolution: "postcss-loader@npm:7.3.4" dependencies: - cosmiconfig: "npm:^8.2.0" - jiti: "npm:^1.18.2" - semver: "npm:^7.3.8" + cosmiconfig: "npm:^8.3.5" + jiti: "npm:^1.20.0" + semver: "npm:^7.5.4" peerDependencies: postcss: ^7.0.0 || ^8.0.1 webpack: ^5.0.0 - checksum: 743a4286db68169d271bef31e6e9351874bcf2dfa408b82c648c2d5bfba9c862cbfe3004494d927469654d6ac8b82fe647f2b80a186c1dbd44d81632eec1e838 + checksum: 234b01149a966a6190290c6d265b8e3df10f43262dd679451c1e7370bae74e27b746b02e660d204b901e3cf1ad28759c2679a93c64a3eb499169d8dec39df1c1 languageName: node linkType: hard @@ -23665,12 +23670,12 @@ __metadata: languageName: node linkType: hard -"postcss-scss@npm:4.0.6, postcss-scss@npm:^4.0.6": - version: 4.0.6 - resolution: "postcss-scss@npm:4.0.6" +"postcss-scss@npm:4.0.9, postcss-scss@npm:^4.0.6": + version: 4.0.9 + resolution: "postcss-scss@npm:4.0.9" peerDependencies: - postcss: ^8.4.19 - checksum: fa436a2c92555135f07135586798089b4d8b31ad9d7f3352563e5c9b722e8ff64c32f95071541f87bc78b63dc6dd1475a68c4683b05e5618aaf55adfc3b007d7 + postcss: ^8.4.29 + checksum: d191c771344357a28995a2f53041ec699070331b8238e076001cedde97215bd3ebf596d0a9882b22c566977c4b72816dafc00028dc09153c6f97f71cd28a70f7 languageName: node linkType: hard @@ -23714,14 +23719,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.31, postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.28": - version: 8.4.31 - resolution: "postcss@npm:8.4.31" +"postcss@npm:8.4.33, postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.28": + version: 8.4.33 + resolution: "postcss@npm:8.4.33" dependencies: - nanoid: "npm:^3.3.6" + nanoid: "npm:^3.3.7" picocolors: "npm:^1.0.0" source-map-js: "npm:^1.0.2" - checksum: 1a6653e72105907377f9d4f2cd341d8d90e3fde823a5ddea1e2237aaa56933ea07853f0f2758c28892a1d70c53bbaca200eb8b80f8ed55f13093003dbec5afa0 + checksum: e22a4594c255f26117f38419fb494d7ecab0f596cd409f7aadc8a6173abf180ed7ea970cd13fd366ab12b5840be901d2a09b25197700c2ebcb5a8077326bf519 languageName: node linkType: hard @@ -24413,23 +24418,7 @@ __metadata: languageName: node linkType: hard -"rc-tree@npm:5.8.0": - version: 5.8.0 - resolution: "rc-tree@npm:5.8.0" - dependencies: - "@babel/runtime": "npm:^7.10.1" - classnames: "npm:2.x" - rc-motion: "npm:^2.0.1" - rc-util: "npm:^5.16.1" - rc-virtual-list: "npm:^3.5.1" - peerDependencies: - react: "*" - react-dom: "*" - checksum: 130cc89f582aedbe252590f8078bd39535ed2de43fa7bf3be88695065d15405768340fb26dda12d90601296afd439d876ce859d4604659a6adde4f783ff7f26a - languageName: node - linkType: hard - -"rc-tree@npm:~5.8.1": +"rc-tree@npm:5.8.2, rc-tree@npm:~5.8.1": version: 5.8.2 resolution: "rc-tree@npm:5.8.2" dependencies: @@ -24501,13 +24490,13 @@ __metadata: languageName: node linkType: hard -"re-resizable@npm:6.9.9": - version: 6.9.9 - resolution: "re-resizable@npm:6.9.9" +"re-resizable@npm:6.9.11": + version: 6.9.11 + resolution: "re-resizable@npm:6.9.11" peerDependencies: react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - checksum: c2e22bfeca9765b75d33b0e9135b0034684c6fa6b11927d81e464f70b7c5cf20176fd52d128ab3ee342ca0271357efdca2c4856a80e174b58101349bba35c11c + checksum: 3f2590374d03a6b5f7ebc26f273bdb461ceecb1322adf3b7925c695b1c6fa0841225feb79cf63d19c3c2451a9a8ed4f4a82fa119f3a22565ce78e0619d2b624c languageName: node linkType: hard @@ -24675,20 +24664,7 @@ __metadata: languageName: node linkType: hard -"react-draggable@npm:4.4.5": - version: 4.4.5 - resolution: "react-draggable@npm:4.4.5" - dependencies: - clsx: "npm:^1.1.1" - prop-types: "npm:^15.8.1" - peerDependencies: - react: ">= 16.3.0" - react-dom: ">= 16.3.0" - checksum: a6af765a71a62636a9c12868e9015e86e0160fbd9218a895200813f502e9ff848b8aab16ff7177faa808dd5a498b8a03c355edd2be0b823ec1035e91edf2103d - languageName: node - linkType: hard - -"react-draggable@npm:^4.0.0, react-draggable@npm:^4.0.3, react-draggable@npm:^4.4.5": +"react-draggable@npm:4.4.6, react-draggable@npm:^4.0.0, react-draggable@npm:^4.0.3, react-draggable@npm:^4.4.5": version: 4.4.6 resolution: "react-draggable@npm:4.4.6" dependencies: @@ -24780,9 +24756,9 @@ __metadata: languageName: node linkType: hard -"react-grid-layout@npm:1.4.2": - version: 1.4.2 - resolution: "react-grid-layout@npm:1.4.2" +"react-grid-layout@npm:1.4.4": + version: 1.4.4 + resolution: "react-grid-layout@npm:1.4.4" dependencies: clsx: "npm:^2.0.0" fast-equals: "npm:^4.0.3" @@ -24793,7 +24769,7 @@ __metadata: peerDependencies: react: ">= 16.3.0" react-dom: ">= 16.3.0" - checksum: 651819b1b5af8d57cd7ee702fa367f43e00c77be6403b5ab423179207be340a01d8bf9cb61e76fefafec40a8aacbcb2f47efb902eef77eedb6ce56f3716a3408 + checksum: 43c9bc7e8ce5a902720ebe559b1551724615c617391b040a0a275597748e1927b293c5ddcb73053b1925909e1c293948b4969a35799d541bf9d8886e07ac0085 languageName: node linkType: hard @@ -24811,11 +24787,11 @@ __metadata: linkType: hard "react-hook-form@npm:^7.49.2": - version: 7.49.2 - resolution: "react-hook-form@npm:7.49.2" + version: 7.49.3 + resolution: "react-hook-form@npm:7.49.3" peerDependencies: react: ^16.8.0 || ^17 || ^18 - checksum: 7895d65b8458c42d46eb338803bb0fd1aab42fc69ecf80b47846eace9493a10cac5b05c9b744a5f9f1f7969a3e2703fc2118cdab97e49a7798a72d09f106383f + checksum: ccd35d73f26b56c2933312c5d445552aab8c20a02ab07360808f039c9daf37a046a0afa2c2c56fac0a16b1963ae3e4ebce37136d14388002d00d6c5483e3fdb7 languageName: node linkType: hard