From 564483652230b9a100f733b7214271401b423d31 Mon Sep 17 00:00:00 2001 From: Santiago Date: Thu, 19 Jan 2023 15:36:35 -0300 Subject: [PATCH 1/5] Capture and expose notification delivery errors (#31) This PR makes it possible to store the last error for each receiver in case of notification delivery failure. These errors are exposed via the `/api/v2/receivers` endpoint. Co-authored-by: gotjosh --- .gitignore | 4 + api/api.go | 5 +- api/v2/api.go | 47 ++++++++++-- api/v2/api_test.go | 7 +- api/v2/models/integration.go | 122 +++++++++++++++++++++++++++++++ api/v2/models/receiver.go | 51 +++++++++++++ api/v2/openapi.yaml | 28 +++++++ api/v2/restapi/embedded_spec.go | 82 ++++++++++++++++++++- cmd/alertmanager/main.go | 26 ++++--- config/receiver/receiver.go | 4 +- config/receiver/receiver_test.go | 4 +- notify/notify.go | 68 +++++++++++------ notify/notify_test.go | 10 +-- notify/receiver.go | 42 +++++++++++ 14 files changed, 448 insertions(+), 52 deletions(-) create mode 100644 api/v2/models/integration.go create mode 100644 notify/receiver.go diff --git a/.gitignore b/.gitignore index 7ef77d321a..26a705f498 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ !/.promu.yml !/api/v2/openapi.yaml !.github/workflows/*.yml + +# Editor +.vscode +.DS_Store diff --git a/api/api.go b/api/api.go index 2e1e1ea425..facbf56fc9 100644 --- a/api/api.go +++ b/api/api.go @@ -29,6 +29,7 @@ import ( "github.com/prometheus/alertmanager/cluster" "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/dispatch" + "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/provider" "github.com/prometheus/alertmanager/silence" "github.com/prometheus/alertmanager/types" @@ -186,8 +187,8 @@ func (api *API) Register(r *route.Router, routePrefix string) *http.ServeMux { // Update config and resolve timeout of each API. APIv2 also needs // setAlertStatus to be updated. -func (api *API) Update(cfg *config.Config, setAlertStatus func(model.LabelSet)) { - api.v2.Update(cfg, setAlertStatus) +func (api *API) Update(cfg *config.Config, receivers []*notify.Receiver, setAlertStatus func(model.LabelSet)) { + api.v2.Update(cfg, setAlertStatus, receivers) } func (api *API) limitHandler(h http.Handler) http.Handler { diff --git a/api/v2/api.go b/api/v2/api.go index b4f57e75e2..6b20501ae3 100644 --- a/api/v2/api.go +++ b/api/v2/api.go @@ -33,7 +33,6 @@ import ( "github.com/prometheus/common/version" "github.com/rs/cors" - "github.com/prometheus/alertmanager/api/metrics" open_api_models "github.com/prometheus/alertmanager/api/v2/models" "github.com/prometheus/alertmanager/api/v2/restapi" "github.com/prometheus/alertmanager/api/v2/restapi/operations" @@ -42,10 +41,13 @@ import ( general_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/general" receiver_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver" silence_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/silence" + + "github.com/prometheus/alertmanager/api/metrics" "github.com/prometheus/alertmanager/cluster" "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/dispatch" "github.com/prometheus/alertmanager/matchers/compat" + "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/pkg/labels" "github.com/prometheus/alertmanager/provider" "github.com/prometheus/alertmanager/silence" @@ -73,7 +75,8 @@ type API struct { logger log.Logger m *metrics.Alerts - Handler http.Handler + Handler http.Handler + receivers []*notify.Receiver } type ( @@ -155,13 +158,14 @@ func (api *API) requestLogger(req *http.Request) log.Logger { } // Update sets the API struct members that may change between reloads of alertmanager. -func (api *API) Update(cfg *config.Config, setAlertStatus setAlertStatusFn) { +func (api *API) Update(cfg *config.Config, setAlertStatus setAlertStatusFn, receivers []*notify.Receiver) { api.mtx.Lock() defer api.mtx.Unlock() api.alertmanagerConfig = cfg api.route = dispatch.NewRoute(cfg.Route, nil) api.setAlertStatus = setAlertStatus + api.receivers = receivers } func (api *API) getStatusHandler(params general_ops.GetStatusParams) middleware.Responder { @@ -222,11 +226,40 @@ func (api *API) getStatusHandler(params general_ops.GetStatusParams) middleware. func (api *API) getReceiversHandler(params receiver_ops.GetReceiversParams) middleware.Responder { api.mtx.RLock() - defer api.mtx.RUnlock() + configReceivers := api.receivers + api.mtx.RUnlock() + + receivers := make([]*open_api_models.Receiver, 0, len(configReceivers)) + for _, r := range configReceivers { + integrations := make([]*open_api_models.Integration, 0, len(r.Integrations())) + + for _, integration := range r.Integrations() { + notify, duration, err := integration.GetReport() + iname := integration.String() + sendResolved := integration.SendResolved() + integrations = append(integrations, &open_api_models.Integration{ + Name: &iname, + SendResolved: &sendResolved, + LastNotifyAttempt: strfmt.DateTime(notify.UTC()), + LastNotifyAttemptDuration: duration.String(), + LastNotifyAttemptError: func() string { + if err != nil { + return err.Error() + } + return "" + }(), + }) + } + + rName := r.Name() + active := r.Active() + model := &open_api_models.Receiver{ + Name: &rName, + Active: &active, + Integrations: integrations, + } - receivers := make([]*open_api_models.Receiver, 0, len(api.alertmanagerConfig.Receivers)) - for i := range api.alertmanagerConfig.Receivers { - receivers = append(receivers, &open_api_models.Receiver{Name: &api.alertmanagerConfig.Receivers[i].Name}) + receivers = append(receivers, model) } return receiver_ops.NewGetReceiversOK().WithPayload(receivers) diff --git a/api/v2/api_test.go b/api/v2/api_test.go index d520dbde13..79e89158d3 100644 --- a/api/v2/api_test.go +++ b/api/v2/api_test.go @@ -33,6 +33,7 @@ import ( receiver_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver" silence_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/silence" "github.com/prometheus/alertmanager/config" + "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/pkg/labels" "github.com/prometheus/alertmanager/silence" "github.com/prometheus/alertmanager/silence/silencepb" @@ -484,6 +485,10 @@ receivers: uptime: time.Now(), logger: log.NewNopLogger(), alertmanagerConfig: cfg, + receivers: []*notify.Receiver{ + notify.NewReceiver("team-X", true, nil), + notify.NewReceiver("team-Y", true, nil), + }, } for _, tc := range []struct { @@ -491,7 +496,7 @@ receivers: expectedCode int }{ { - `[{"name":"team-X"},{"name":"team-Y"}]`, + `[{"active":true,"integrations":[],"name":"team-X"},{"active":true,"integrations":[],"name":"team-Y"}]`, 200, }, } { diff --git a/api/v2/models/integration.go b/api/v2/models/integration.go new file mode 100644 index 0000000000..b3f8f2a9a8 --- /dev/null +++ b/api/v2/models/integration.go @@ -0,0 +1,122 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// Integration integration +// +// swagger:model integration +type Integration struct { + + // A timestamp indicating the last attempt to deliver a notification regardless of the outcome. + // Format: date-time + LastNotifyAttempt strfmt.DateTime `json:"lastNotifyAttempt,omitempty"` + + // Duration of the last attempt to deliver a notification in humanized format (`1s` or `15ms`, etc). + LastNotifyAttemptDuration string `json:"lastNotifyAttemptDuration,omitempty"` + + // Error string for the last attempt to deliver a notification. Empty if the last attempt was successful. + LastNotifyAttemptError string `json:"lastNotifyAttemptError,omitempty"` + + // name + // Required: true + Name *string `json:"name"` + + // send resolved + // Required: true + SendResolved *bool `json:"sendResolved"` +} + +// Validate validates this integration +func (m *Integration) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLastNotifyAttempt(formats); err != nil { + res = append(res, err) + } + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSendResolved(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Integration) validateLastNotifyAttempt(formats strfmt.Registry) error { + + if swag.IsZero(m.LastNotifyAttempt) { // not required + return nil + } + + if err := validate.FormatOf("lastNotifyAttempt", "body", "date-time", m.LastNotifyAttempt.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *Integration) validateName(formats strfmt.Registry) error { + + if err := validate.Required("name", "body", m.Name); err != nil { + return err + } + + return nil +} + +func (m *Integration) validateSendResolved(formats strfmt.Registry) error { + + if err := validate.Required("sendResolved", "body", m.SendResolved); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *Integration) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Integration) UnmarshalBinary(b []byte) error { + var res Integration + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/api/v2/models/receiver.go b/api/v2/models/receiver.go index 8e1bf9ee45..bc089bd12f 100644 --- a/api/v2/models/receiver.go +++ b/api/v2/models/receiver.go @@ -20,6 +20,7 @@ package models // Editing this file might prove futile when you re-run the swagger generate command import ( + "strconv" "context" "github.com/go-openapi/errors" @@ -33,6 +34,14 @@ import ( // swagger:model receiver type Receiver struct { + // active + // Required: true + Active *bool `json:"active"` + + // integrations + // Required: true + Integrations []*Integration `json:"integrations"` + // name // Required: true Name *string `json:"name"` @@ -42,6 +51,14 @@ type Receiver struct { func (m *Receiver) Validate(formats strfmt.Registry) error { var res []error + if err := m.validateActive(formats); err != nil { + res = append(res, err) + } + + if err := m.validateIntegrations(formats); err != nil { + res = append(res, err) + } + if err := m.validateName(formats); err != nil { res = append(res, err) } @@ -52,6 +69,40 @@ func (m *Receiver) Validate(formats strfmt.Registry) error { return nil } +func (m *Receiver) validateActive(formats strfmt.Registry) error { + + if err := validate.Required("active", "body", m.Active); err != nil { + return err + } + + return nil +} + +func (m *Receiver) validateIntegrations(formats strfmt.Registry) error { + + if err := validate.Required("integrations", "body", m.Integrations); err != nil { + return err + } + + for i := 0; i < len(m.Integrations); i++ { + if swag.IsZero(m.Integrations[i]) { // not required + continue + } + + if m.Integrations[i] != nil { + if err := m.Integrations[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("integrations" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + func (m *Receiver) validateName(formats strfmt.Registry) error { if err := validate.Required("name", "body", m.Name); err != nil { diff --git a/api/v2/openapi.yaml b/api/v2/openapi.yaml index 549cc33e7f..c956a94d39 100644 --- a/api/v2/openapi.yaml +++ b/api/v2/openapi.yaml @@ -510,8 +510,36 @@ definitions: properties: name: type: string + active: + type: boolean + integrations: + type: array + items: + $ref: '#/definitions/integration' + required: + - name + - active + - integrations + integration: + type: object + properties: + name: + type: string + sendResolved: + type: boolean + lastNotifyAttempt: + description: A timestamp indicating the last attempt to deliver a notification regardless of the outcome. + type: string + format: date-time + lastNotifyAttemptDuration: + description: Duration of the last attempt to deliver a notification in humanized format (`1s` or `15ms`, etc). + type: string + lastNotifyAttemptError: + description: Error string for the last attempt to deliver a notification. Empty if the last attempt was successful. + type: string required: - name + - sendResolved labelSet: type: object additionalProperties: diff --git a/api/v2/restapi/embedded_spec.go b/api/v2/restapi/embedded_spec.go index 0e23efd060..87a920764f 100644 --- a/api/v2/restapi/embedded_spec.go +++ b/api/v2/restapi/embedded_spec.go @@ -605,6 +605,34 @@ func init() { "$ref": "#/definitions/gettableSilence" } }, + "integration": { + "type": "object", + "required": [ + "name", + "sendResolved" + ], + "properties": { + "lastNotifyAttempt": { + "description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.", + "type": "string", + "format": "date-time" + }, + "lastNotifyAttemptDuration": { + "description": "Duration of the last attempt to deliver a notification in humanized format (` + "`" + `1s` + "`" + ` or ` + "`" + `15ms` + "`" + `, etc).", + "type": "string" + }, + "lastNotifyAttemptError": { + "description": "Error string for the last attempt to deliver a notification. Empty if the last attempt was successful.", + "type": "string" + }, + "name": { + "type": "string" + }, + "sendResolved": { + "type": "boolean" + } + } + }, "labelSet": { "type": "object", "additionalProperties": { @@ -703,9 +731,20 @@ func init() { "receiver": { "type": "object", "required": [ - "name" + "name", + "active", + "integrations" ], "properties": { + "active": { + "type": "boolean" + }, + "integrations": { + "type": "array", + "items": { + "$ref": "#/definitions/integration" + } + }, "name": { "type": "string" } @@ -1428,6 +1467,34 @@ func init() { "$ref": "#/definitions/gettableSilence" } }, + "integration": { + "type": "object", + "required": [ + "name", + "sendResolved" + ], + "properties": { + "lastNotifyAttempt": { + "description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.", + "type": "string", + "format": "date-time" + }, + "lastNotifyAttemptDuration": { + "description": "Duration of the last attempt to deliver a notification in humanized format (` + "`" + `1s` + "`" + ` or ` + "`" + `15ms` + "`" + `, etc).", + "type": "string" + }, + "lastNotifyAttemptError": { + "description": "Error string for the last attempt to deliver a notification. Empty if the last attempt was successful.", + "type": "string" + }, + "name": { + "type": "string" + }, + "sendResolved": { + "type": "boolean" + } + } + }, "labelSet": { "type": "object", "additionalProperties": { @@ -1526,9 +1593,20 @@ func init() { "receiver": { "type": "object", "required": [ - "name" + "name", + "active", + "integrations" ], "properties": { + "active": { + "type": "boolean" + }, + "integrations": { + "type": "array", + "items": { + "$ref": "#/definitions/integration" + } + }, "name": { "type": "string" } diff --git a/cmd/alertmanager/main.go b/cmd/alertmanager/main.go index b2938189d5..6a5fbd63f5 100644 --- a/cmd/alertmanager/main.go +++ b/cmd/alertmanager/main.go @@ -380,26 +380,26 @@ func run() int { // Build the routing tree and record which receivers are used. routes := dispatch.NewRoute(conf.Route, nil) - activeReceivers := make(map[string]struct{}) + activeReceiversMap := make(map[string]struct{}) routes.Walk(func(r *dispatch.Route) { - activeReceivers[r.RouteOpts.Receiver] = struct{}{} + activeReceiversMap[r.RouteOpts.Receiver] = struct{}{} }) // Build the map of receiver to integrations. - receivers := make(map[string][]notify.Integration, len(activeReceivers)) + receivers := make([]*notify.Receiver, 0, len(activeReceiversMap)) var integrationsNum int for _, rcv := range conf.Receivers { - if _, found := activeReceivers[rcv.Name]; !found { + if _, found := activeReceiversMap[rcv.Name]; !found { // No need to build a receiver if no route is using it. level.Info(configLogger).Log("msg", "skipping creation of receiver not referenced by any route", "receiver", rcv.Name) + receivers = append(receivers, notify.NewReceiver(rcv.Name, false, nil)) continue } integrations, err := receiver.BuildReceiverIntegrations(rcv, tmpl, logger) if err != nil { return err } - // rcv.Name is guaranteed to be unique across all receivers. - receivers[rcv.Name] = integrations + receivers = append(receivers, notify.NewReceiver(rcv.Name, true, integrations)) integrationsNum += len(integrations) } @@ -429,8 +429,16 @@ func run() int { pipelinePeer = peer } + activeReceivers := make([]*notify.Receiver, 0, len(receivers)) + for i := range receivers { + if !receivers[i].Active() { + continue + } + activeReceivers = append(activeReceivers, receivers[i]) + } + pipeline := pipelineBuilder.New( - receivers, + activeReceivers, waitFunc, inhibitor, silencer, @@ -439,11 +447,11 @@ func run() int { pipelinePeer, ) - configuredReceivers.Set(float64(len(activeReceivers))) + configuredReceivers.Set(float64(len(activeReceiversMap))) configuredIntegrations.Set(float64(integrationsNum)) configuredInhibitionRules.Set(float64(len(conf.InhibitRules))) - api.Update(conf, func(labels model.LabelSet) { + api.Update(conf, receivers, func(labels model.LabelSet) { inhibitor.Mutes(labels) silencer.Mutes(labels) }) diff --git a/config/receiver/receiver.go b/config/receiver/receiver.go index 9bb039ef05..fdbf35e698 100644 --- a/config/receiver/receiver.go +++ b/config/receiver/receiver.go @@ -39,10 +39,10 @@ import ( // BuildReceiverIntegrations builds a list of integration notifiers off of a // receiver config. -func BuildReceiverIntegrations(nc config.Receiver, tmpl *template.Template, logger log.Logger, httpOpts ...commoncfg.HTTPClientOption) ([]notify.Integration, error) { +func BuildReceiverIntegrations(nc config.Receiver, tmpl *template.Template, logger log.Logger, httpOpts ...commoncfg.HTTPClientOption) ([]*notify.Integration, error) { var ( errs types.MultiError - integrations []notify.Integration + integrations []*notify.Integration add = func(name string, i int, rs notify.ResolvedSender, f func(l log.Logger) (notify.Notifier, error)) { n, err := f(log.With(logger, "integration", name)) if err != nil { diff --git a/config/receiver/receiver_test.go b/config/receiver/receiver_test.go index 3d146a98d0..e19820e99c 100644 --- a/config/receiver/receiver_test.go +++ b/config/receiver/receiver_test.go @@ -31,7 +31,7 @@ func TestBuildReceiverIntegrations(t *testing.T) { for _, tc := range []struct { receiver config.Receiver err bool - exp []notify.Integration + exp []*notify.Integration }{ { receiver: config.Receiver{ @@ -48,7 +48,7 @@ func TestBuildReceiverIntegrations(t *testing.T) { }, }, }, - exp: []notify.Integration{ + exp: []*notify.Integration{ notify.NewIntegration(nil, sendResolved(false), "webhook", 0, "foo"), notify.NewIntegration(nil, sendResolved(true), "webhook", 1, "foo"), }, diff --git a/notify/notify.go b/notify/notify.go index 30861a3027..64e0147eb4 100644 --- a/notify/notify.go +++ b/notify/notify.go @@ -67,11 +67,16 @@ type Integration struct { name string idx int receiverName string + + mtx sync.RWMutex + lastNotifyAttempt time.Time + lastNotifyAttemptDuration model.Duration + lastNotifyAttemptError error } // NewIntegration returns a new integration. -func NewIntegration(notifier Notifier, rs ResolvedSender, name string, idx int, receiverName string) Integration { - return Integration{ +func NewIntegration(notifier Notifier, rs ResolvedSender, name string, idx int, receiverName string) *Integration { + return &Integration{ notifier: notifier, rs: rs, name: name, @@ -100,6 +105,22 @@ func (i *Integration) Index() int { return i.idx } +func (i *Integration) Report(start time.Time, duration model.Duration, notifyError error) { + i.mtx.Lock() + defer i.mtx.Unlock() + + i.lastNotifyAttempt = start + i.lastNotifyAttemptDuration = duration + i.lastNotifyAttemptError = notifyError +} + +func (i *Integration) GetReport() (time.Time, model.Duration, error) { + i.mtx.RLock() + defer i.mtx.RUnlock() + + return i.lastNotifyAttempt, i.lastNotifyAttemptDuration, i.lastNotifyAttemptError +} + // String implements the Stringer interface. func (i *Integration) String() string { return fmt.Sprintf("%s[%d]", i.name, i.idx) @@ -308,7 +329,7 @@ func NewMetrics(r prometheus.Registerer, ff featurecontrol.Flagger) *Metrics { return m } -func (m *Metrics) InitializeFor(receiver map[string][]Integration) { +func (m *Metrics) InitializeFor(receivers []*Receiver) { if m.ff.EnableReceiverNamesInMetrics() { // Reset the vectors to take into account receiver names changing after hot reloads. @@ -318,8 +339,9 @@ func (m *Metrics) InitializeFor(receiver map[string][]Integration) { m.notificationLatencySeconds.Reset() m.numTotalFailedNotifications.Reset() - for name, integrations := range receiver { - for _, integration := range integrations { + for _, receiver := range receivers { + name := receiver.Name() + for _, integration := range receiver.Integrations() { m.numNotifications.WithLabelValues(integration.Name(), name) m.numNotificationRequestsTotal.WithLabelValues(integration.Name(), name) @@ -376,7 +398,7 @@ func NewPipelineBuilder(r prometheus.Registerer, ff featurecontrol.Flagger) *Pip // New returns a map of receivers to Stages. func (pb *PipelineBuilder) New( - receivers map[string][]Integration, + receivers []*Receiver, wait func() time.Duration, inhibitor *inhibit.Inhibitor, silencer *silence.Silencer, @@ -392,9 +414,9 @@ func (pb *PipelineBuilder) New( tms := NewTimeMuteStage(intervener, pb.metrics) ss := NewMuteStage(silencer, pb.metrics) - for name := range receivers { - st := createReceiverStage(name, receivers[name], wait, notificationLog, pb.metrics) - rs[name] = MultiStage{ms, is, tas, tms, ss, st} + for _, r := range receivers { + st := createReceiverStage(r, wait, notificationLog, pb.metrics) + rs[r.groupName] = MultiStage{ms, is, tas, tms, ss, st} } pb.metrics.InitializeFor(receivers) @@ -404,23 +426,22 @@ func (pb *PipelineBuilder) New( // createReceiverStage creates a pipeline of stages for a receiver. func createReceiverStage( - name string, - integrations []Integration, + receiver *Receiver, wait func() time.Duration, notificationLog NotificationLog, metrics *Metrics, ) Stage { var fs FanoutStage - for i := range integrations { + for i := range receiver.integrations { recv := &nflogpb.Receiver{ - GroupName: name, - Integration: integrations[i].Name(), - Idx: uint32(integrations[i].Index()), + GroupName: receiver.groupName, + Integration: receiver.integrations[i].Name(), + Idx: uint32(receiver.integrations[i].Index()), } var s MultiStage s = append(s, NewWaitStage(wait)) - s = append(s, NewDedupStage(&integrations[i], notificationLog, recv)) - s = append(s, NewRetryStage(integrations[i], name, metrics)) + s = append(s, NewDedupStage(receiver.integrations[i], notificationLog, recv)) + s = append(s, NewRetryStage(receiver.integrations[i], receiver.groupName, metrics)) s = append(s, NewSetNotifiesStage(notificationLog, recv)) fs = append(fs, s) @@ -733,14 +754,14 @@ func (n *DedupStage) Exec(ctx context.Context, _ log.Logger, alerts ...*types.Al // RetryStage notifies via passed integration with exponential backoff until it // succeeds. It aborts if the context is canceled or timed out. type RetryStage struct { - integration Integration + integration *Integration groupName string metrics *Metrics labelValues []string } // NewRetryStage returns a new instance of a RetryStage. -func NewRetryStage(i Integration, groupName string, metrics *Metrics) *RetryStage { +func NewRetryStage(i *Integration, groupName string, metrics *Metrics) *RetryStage { labelValues := []string{i.Name()} if metrics.ff.EnableReceiverNamesInMetrics() { @@ -834,9 +855,12 @@ func (r RetryStage) exec(ctx context.Context, l log.Logger, alerts ...*types.Ale case <-tick.C: now := time.Now() retry, err := r.integration.Notify(ctx, sent...) - dur := time.Since(now) - r.metrics.notificationLatencySeconds.WithLabelValues(r.labelValues...).Observe(dur.Seconds()) + + duration := time.Since(now) + r.metrics.notificationLatencySeconds.WithLabelValues(r.labelValues...).Observe(duration.Seconds()) r.metrics.numNotificationRequestsTotal.WithLabelValues(r.labelValues...).Inc() + + r.integration.Report(now, model.Duration(duration), err) if err != nil { r.metrics.numNotificationRequestsFailedTotal.WithLabelValues(r.labelValues...).Inc() if !retry { @@ -857,7 +881,7 @@ func (r RetryStage) exec(ctx context.Context, l log.Logger, alerts ...*types.Ale lvl = level.Debug(log.With(l, "alerts", fmt.Sprintf("%v", alerts))) } - lvl.Log("msg", "Notify success", "attempts", i, "duration", dur) + lvl.Log("msg", "Notify success", "attempts", i, "duration", duration) return ctx, alerts, nil } case <-ctx.Done(): diff --git a/notify/notify_test.go b/notify/notify_test.go index d5ce9612e3..6411f1f91d 100644 --- a/notify/notify_test.go +++ b/notify/notify_test.go @@ -381,7 +381,7 @@ func TestRoutingStage(t *testing.T) { func TestRetryStageWithError(t *testing.T) { fail, retry := true, true sent := []*types.Alert{} - i := Integration{ + i := &Integration{ notifier: notifierFunc(func(ctx context.Context, alerts ...*types.Alert) (bool, error) { if fail { fail = false @@ -435,7 +435,7 @@ func TestRetryStageWithErrorCode(t *testing.T) { for _, testData := range testcases { retry := false testData := testData - i := Integration{ + i := &Integration{ name: "test", notifier: notifierFunc(func(ctx context.Context, alerts ...*types.Alert) (bool, error) { if !testData.isNewErrorWithReason { @@ -472,7 +472,7 @@ func TestRetryStageWithErrorCode(t *testing.T) { func TestRetryStageWithContextCanceled(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - i := Integration{ + i := &Integration{ name: "test", notifier: notifierFunc(func(ctx context.Context, alerts ...*types.Alert) (bool, error) { cancel() @@ -504,7 +504,7 @@ func TestRetryStageWithContextCanceled(t *testing.T) { func TestRetryStageNoResolved(t *testing.T) { sent := []*types.Alert{} - i := Integration{ + i := &Integration{ notifier: notifierFunc(func(ctx context.Context, alerts ...*types.Alert) (bool, error) { sent = append(sent, alerts...) return false, nil @@ -555,7 +555,7 @@ func TestRetryStageNoResolved(t *testing.T) { func TestRetryStageSendResolved(t *testing.T) { sent := []*types.Alert{} - i := Integration{ + i := &Integration{ notifier: notifierFunc(func(ctx context.Context, alerts ...*types.Alert) (bool, error) { sent = append(sent, alerts...) return false, nil diff --git a/notify/receiver.go b/notify/receiver.go new file mode 100644 index 0000000000..d8bc1d0dfc --- /dev/null +++ b/notify/receiver.go @@ -0,0 +1,42 @@ +// Copyright 2022 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package notify + +type Receiver struct { + groupName string + integrations []*Integration + + // A receiver is considered active if a route is using it. + active bool +} + +func (r *Receiver) Name() string { + return r.groupName +} + +func (r *Receiver) Active() bool { + return r.active +} + +func (r *Receiver) Integrations() []*Integration { + return r.integrations +} + +func NewReceiver(name string, active bool, integrations []*Integration) *Receiver { + return &Receiver{ + groupName: name, + active: active, + integrations: integrations, + } +} From 9175bebcbaea863fe3e35aa2b5c46d8ecefaaac0 Mon Sep 17 00:00:00 2001 From: Alex Weaver Date: Fri, 27 Oct 2023 11:37:35 -0500 Subject: [PATCH 2/5] regen swagger --- api/v2/models/integration.go | 8 +++++++- api/v2/models/receiver.go | 40 ++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/api/v2/models/integration.go b/api/v2/models/integration.go index b3f8f2a9a8..46f903826d 100644 --- a/api/v2/models/integration.go +++ b/api/v2/models/integration.go @@ -20,6 +20,8 @@ package models // Editing this file might prove futile when you re-run the swagger generate command import ( + "context" + "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" @@ -73,7 +75,6 @@ func (m *Integration) Validate(formats strfmt.Registry) error { } func (m *Integration) validateLastNotifyAttempt(formats strfmt.Registry) error { - if swag.IsZero(m.LastNotifyAttempt) { // not required return nil } @@ -103,6 +104,11 @@ func (m *Integration) validateSendResolved(formats strfmt.Registry) error { return nil } +// ContextValidate validates this integration based on context it is used +func (m *Integration) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + // MarshalBinary interface implementation func (m *Integration) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/api/v2/models/receiver.go b/api/v2/models/receiver.go index bc089bd12f..8c248ea737 100644 --- a/api/v2/models/receiver.go +++ b/api/v2/models/receiver.go @@ -20,8 +20,8 @@ package models // Editing this file might prove futile when you re-run the swagger generate command import ( - "strconv" "context" + "strconv" "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" @@ -93,6 +93,8 @@ func (m *Receiver) validateIntegrations(formats strfmt.Registry) error { if err := m.Integrations[i].Validate(formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("integrations" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("integrations" + "." + strconv.Itoa(i)) } return err } @@ -112,8 +114,42 @@ func (m *Receiver) validateName(formats strfmt.Registry) error { return nil } -// ContextValidate validates this receiver based on context it is used +// ContextValidate validate this receiver based on the context it is used func (m *Receiver) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateIntegrations(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Receiver) contextValidateIntegrations(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Integrations); i++ { + + if m.Integrations[i] != nil { + + if swag.IsZero(m.Integrations[i]) { // not required + return nil + } + + if err := m.Integrations[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("integrations" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("integrations" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + return nil } From 3478d1191a31d627f70fa78d84b59b0e8b2bf151 Mon Sep 17 00:00:00 2001 From: Santiago Date: Mon, 18 Mar 2024 16:24:30 +0100 Subject: [PATCH 3/5] Add Upsert method to Silences --- silence/silence.go | 19 ++++++++++++++++++ silence/silence_test.go | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/silence/silence.go b/silence/silence.go index 710323f747..4312b7b6b7 100644 --- a/silence/silence.go +++ b/silence/silence.go @@ -610,6 +610,25 @@ func (s *Silences) Set(sil *pb.Silence) (string, error) { return sil.Id, s.setSilence(sil, now, false) } +// Upsert allows creating silences with a predefined ID. +func (s *Silences) Upsert(sil *pb.Silence) (string, error) { + id, err := s.Set(sil) + if !errors.Is(err, ErrNotFound) { + return id, err + } + + // If the silence was not found, create it with the given ID. + s.mtx.Lock() + defer s.mtx.Unlock() + + now := s.nowUTC() + if sil.StartsAt.Before(now) { + sil.StartsAt = now + } + + return sil.Id, s.setSilence(sil, now, false) +} + // canUpdate returns true if silence a can be updated to b without // affecting the historic view of silencing. func canUpdate(a, b *pb.Silence, now time.Time) bool { diff --git a/silence/silence_test.go b/silence/silence_test.go index 2a880dd3b6..3311869969 100644 --- a/silence/silence_test.go +++ b/silence/silence_test.go @@ -459,6 +459,50 @@ func TestSilenceSet(t *testing.T) { require.Equal(t, want, s.st, "unexpected state after silence creation") } +func TestSilenceUpsert(t *testing.T) { + s, err := New(Options{ + Retention: time.Hour, + }) + require.NoError(t, err) + + clock := clock.NewMock() + s.clock = clock + + // Insert silence with predefined id. + clock.Add(time.Minute) + start := s.nowUTC() + + testID := "some_id" + sil := &pb.Silence{ + Id: testID, + Matchers: []*pb.Matcher{{Name: "a", Pattern: "b"}}, + StartsAt: start.Add(2 * time.Minute), + EndsAt: start.Add(5 * time.Minute), + } + id, err := s.Upsert(sil) + require.NoError(t, err) + require.Equal(t, testID, id) + + want := state{ + id: &pb.MeshSilence{ + Silence: &pb.Silence{ + Id: testID, + Matchers: []*pb.Matcher{{Name: "a", Pattern: "b"}}, + StartsAt: start.Add(2 * time.Minute), + EndsAt: start.Add(5 * time.Minute), + UpdatedAt: start, + }, + ExpiresAt: start.Add(5*time.Minute + s.retention), + }, + } + require.Equal(t, want, s.st, "unexpected state after silence creation") + + // Trying to insert an invalid silence should fail. + clock.Add(time.Minute) + _, err = s.Upsert(&pb.Silence{}) + checkErr(t, "silence invalid", err) +} + func TestSetActiveSilence(t *testing.T) { s, err := New(Options{ Retention: time.Hour, From e2f2ed95e68d41b2d3a293b89f70493c9af09663 Mon Sep 17 00:00:00 2001 From: Santiago Date: Tue, 19 Mar 2024 16:22:41 +0100 Subject: [PATCH 4/5] call mtx.Lock() only once --- silence/silence.go | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/silence/silence.go b/silence/silence.go index 4312b7b6b7..1fea036381 100644 --- a/silence/silence.go +++ b/silence/silence.go @@ -573,12 +573,35 @@ func (s *Silences) setSilence(sil *pb.Silence, now time.Time, skipValidate bool) return nil } +// Upsert allows creating silences with a predefined ID. +func (s *Silences) Upsert(sil *pb.Silence) (string, error) { + s.mtx.Lock() + defer s.mtx.Unlock() + + id, err := s.set(sil) + if !errors.Is(err, ErrNotFound) { + return id, err + } + + // If the silence was not found, create it with the given ID. + now := s.nowUTC() + if sil.StartsAt.Before(now) { + sil.StartsAt = now + } + + return sil.Id, s.setSilence(sil, now, false) +} + // Set the specified silence. If a silence with the ID already exists and the modification // modifies history, the old silence gets expired and a new one is created. func (s *Silences) Set(sil *pb.Silence) (string, error) { s.mtx.Lock() defer s.mtx.Unlock() + return s.set(sil) +} +// set assumes a lock is being held in the calling method. +func (s *Silences) set(sil *pb.Silence) (string, error) { now := s.nowUTC() prev, ok := s.getSilence(sil.Id) @@ -610,25 +633,6 @@ func (s *Silences) Set(sil *pb.Silence) (string, error) { return sil.Id, s.setSilence(sil, now, false) } -// Upsert allows creating silences with a predefined ID. -func (s *Silences) Upsert(sil *pb.Silence) (string, error) { - id, err := s.Set(sil) - if !errors.Is(err, ErrNotFound) { - return id, err - } - - // If the silence was not found, create it with the given ID. - s.mtx.Lock() - defer s.mtx.Unlock() - - now := s.nowUTC() - if sil.StartsAt.Before(now) { - sil.StartsAt = now - } - - return sil.Id, s.setSilence(sil, now, false) -} - // canUpdate returns true if silence a can be updated to b without // affecting the historic view of silencing. func canUpdate(a, b *pb.Silence, now time.Time) bool { From d7a8bacbc72280cf33333507d89ce1ebfa728dde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 15:44:22 +0000 Subject: [PATCH 5/5] Bump @mui/material from 5.11.10 to 5.15.14 in /ui/react-app Bumps [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) from 5.11.10 to 5.15.14. - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/next/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v5.15.14/packages/mui-material) --- updated-dependencies: - dependency-name: "@mui/material" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- ui/react-app/package-lock.json | 516 ++++++++++++++++++--------------- ui/react-app/package.json | 2 +- 2 files changed, 290 insertions(+), 228 deletions(-) diff --git a/ui/react-app/package-lock.json b/ui/react-app/package-lock.json index 4b54c03155..519d554990 100644 --- a/ui/react-app/package-lock.json +++ b/ui/react-app/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@emotion/react": "^11.9.3", "@emotion/styled": "^11.9.3", - "@mui/material": "^5.10.14", + "@mui/material": "^5.15.14", "@tanstack/react-query": "^4.7.1", "mdi-material-ui": "^7.4.0", "react": "^18.0.0", @@ -172,11 +172,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", + "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -253,17 +253,22 @@ } }, "node_modules/@emotion/cache": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", "dependencies": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.3" + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" } }, + "node_modules/@emotion/cache/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/@emotion/hash": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", @@ -278,9 +283,9 @@ } }, "node_modules/@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, "node_modules/@emotion/react": { "version": "11.10.6", @@ -318,9 +323,9 @@ } }, "node_modules/@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, "node_modules/@emotion/styled": { "version": "11.10.6", @@ -358,14 +363,14 @@ } }, "node_modules/@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" }, "node_modules/@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, "node_modules/@esbuild/android-arm": { "version": "0.16.17", @@ -775,6 +780,40 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "dependencies": { + "@floating-ui/dom": "^1.6.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -902,25 +941,24 @@ "dev": true }, "node_modules/@mui/base": { - "version": "5.0.0-alpha.118", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.118.tgz", - "integrity": "sha512-GAEpqhnuHjRaAZLdxFNuOf2GDTp9sUawM46oHZV4VnYPFjXJDkIYFWfIQLONb0nga92OiqS5DD/scGzVKCL0Mw==", - "dependencies": { - "@babel/runtime": "^7.20.13", - "@emotion/is-prop-valid": "^1.2.0", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.9", - "@popperjs/core": "^2.11.6", - "clsx": "^1.2.1", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -934,28 +972,28 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.9.tgz", - "integrity": "sha512-YGEtucQ/Nl91VZkzYaLad47Cdui51n/hW+OQm4210g4N3/nZzBxmGeKfubEalf+ShKH4aYDS86XTO6q/TpZnjQ==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.14.tgz", + "integrity": "sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==", "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/material": { - "version": "5.11.10", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.10.tgz", - "integrity": "sha512-hs1WErbiedqlJIZsljgoil908x4NMp8Lfk8di+5c7o809roqKcFTg2+k3z5ucKvs29AXcsdXrDB/kn2K6dGYIw==", - "dependencies": { - "@babel/runtime": "^7.20.13", - "@mui/base": "5.0.0-alpha.118", - "@mui/core-downloads-tracker": "^5.11.9", - "@mui/system": "^5.11.9", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.9", - "@types/react-transition-group": "^4.4.5", - "clsx": "^1.2.1", - "csstype": "^3.1.1", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.14.tgz", + "integrity": "sha512-kEbRw6fASdQ1SQ7LVdWR5OlWV3y7Y54ZxkLzd6LV5tmz+NpO3MJKZXSfgR0LHMP7meKsPiMm4AuzV0pXDpk/BQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.15.14", + "@mui/system": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1", "react-is": "^18.2.0", "react-transition-group": "^4.4.5" @@ -965,7 +1003,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -987,12 +1025,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.9.tgz", - "integrity": "sha512-XMyVIFGomVCmCm92EvYlgq3zrC9K+J6r7IKl/rBJT2/xVYoRY6uM7jeB+Wxh7kXxnW9Dbqsr2yL3cx6wSD1sAg==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", + "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", "dependencies": { - "@babel/runtime": "^7.20.13", - "@mui/utils": "^5.11.9", + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.15.14", "prop-types": "^15.8.1" }, "engines": { @@ -1000,7 +1038,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -1013,13 +1051,13 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.9.tgz", - "integrity": "sha512-bkh2CjHKOMy98HyOc8wQXEZvhOmDa/bhxMUekFX5IG0/w4f5HJ8R6+K6nakUUYNEgjOWPYzNPrvGB8EcGbhahQ==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", + "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", "dependencies": { - "@babel/runtime": "^7.20.13", - "@emotion/cache": "^11.10.5", - "csstype": "^3.1.1", + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { @@ -1027,7 +1065,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -1044,17 +1082,17 @@ } }, "node_modules/@mui/system": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.9.tgz", - "integrity": "sha512-h6uarf+l3FO6l75Nf7yO+qDGrIoa1DM9nAMCUFZQsNCDKOInRzcptnm8M1w/Z3gVetfeeGoIGAYuYKbft6KZZA==", - "dependencies": { - "@babel/runtime": "^7.20.13", - "@mui/private-theming": "^5.11.9", - "@mui/styled-engine": "^5.11.9", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.9", - "clsx": "^1.2.1", - "csstype": "^3.1.1", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.14.tgz", + "integrity": "sha512-auXLXzUaCSSOLqJXmsAaq7P96VPRXg2Rrz6OHNV7lr+kB8lobUF+/N84Vd9C4G/wvCXYPs5TYuuGBRhcGbiBGg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.15.14", + "@mui/styled-engine": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "clsx": "^2.1.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { @@ -1062,7 +1100,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -1083,11 +1121,11 @@ } }, "node_modules/@mui/types": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", - "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==", + "version": "7.2.14", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", + "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", "peerDependencies": { - "@types/react": "*" + "@types/react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -1096,13 +1134,12 @@ } }, "node_modules/@mui/utils": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.9.tgz", - "integrity": "sha512-eOJaqzcEs4qEwolcvFAmXGpln+uvouvOS9FUX6Wkrte+4I8rZbjODOBDVNlK+V6/ziTfD4iNKC0G+KfOTApbqg==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", + "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", "dependencies": { - "@babel/runtime": "^7.20.13", - "@types/prop-types": "^15.7.5", - "@types/react-is": "^16.7.1 || ^17.0.0", + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -1111,10 +1148,16 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@nodelib/fs.scandir": { @@ -1159,9 +1202,9 @@ "dev": true }, "node_modules/@popperjs/core": { - "version": "2.11.6", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", - "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -1396,9 +1439,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -1431,18 +1474,10 @@ "@types/react": "*" } }, - "node_modules/@types/react-is": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", - "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dependencies": { "@types/react": "*" } @@ -2537,9 +2572,9 @@ } }, "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } @@ -2792,9 +2827,9 @@ } }, "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -6650,9 +6685,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", @@ -8478,11 +8513,11 @@ } }, "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", + "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" } }, "@babel/types": { @@ -8548,15 +8583,22 @@ } }, "@emotion/cache": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", "requires": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.3" + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + }, + "dependencies": { + "stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + } } }, "@emotion/hash": { @@ -8573,9 +8615,9 @@ } }, "@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, "@emotion/react": { "version": "11.10.6", @@ -8605,9 +8647,9 @@ } }, "@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, "@emotion/styled": { "version": "11.10.6", @@ -8634,14 +8676,14 @@ "requires": {} }, "@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" }, "@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, "@esbuild/android-arm": { "version": "0.16.17", @@ -8835,6 +8877,36 @@ "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true }, + "@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "requires": { + "@floating-ui/utils": "^0.2.1" + } + }, + "@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "requires": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "requires": { + "@floating-ui/dom": "^1.6.1" + } + }, + "@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -8937,94 +9009,92 @@ "dev": true }, "@mui/base": { - "version": "5.0.0-alpha.118", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.118.tgz", - "integrity": "sha512-GAEpqhnuHjRaAZLdxFNuOf2GDTp9sUawM46oHZV4VnYPFjXJDkIYFWfIQLONb0nga92OiqS5DD/scGzVKCL0Mw==", - "requires": { - "@babel/runtime": "^7.20.13", - "@emotion/is-prop-valid": "^1.2.0", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.9", - "@popperjs/core": "^2.11.6", - "clsx": "^1.2.1", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "requires": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" } }, "@mui/core-downloads-tracker": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.9.tgz", - "integrity": "sha512-YGEtucQ/Nl91VZkzYaLad47Cdui51n/hW+OQm4210g4N3/nZzBxmGeKfubEalf+ShKH4aYDS86XTO6q/TpZnjQ==" + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.14.tgz", + "integrity": "sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==" }, "@mui/material": { - "version": "5.11.10", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.10.tgz", - "integrity": "sha512-hs1WErbiedqlJIZsljgoil908x4NMp8Lfk8di+5c7o809roqKcFTg2+k3z5ucKvs29AXcsdXrDB/kn2K6dGYIw==", - "requires": { - "@babel/runtime": "^7.20.13", - "@mui/base": "5.0.0-alpha.118", - "@mui/core-downloads-tracker": "^5.11.9", - "@mui/system": "^5.11.9", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.9", - "@types/react-transition-group": "^4.4.5", - "clsx": "^1.2.1", - "csstype": "^3.1.1", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.14.tgz", + "integrity": "sha512-kEbRw6fASdQ1SQ7LVdWR5OlWV3y7Y54ZxkLzd6LV5tmz+NpO3MJKZXSfgR0LHMP7meKsPiMm4AuzV0pXDpk/BQ==", + "requires": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.15.14", + "@mui/system": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1", "react-is": "^18.2.0", "react-transition-group": "^4.4.5" } }, "@mui/private-theming": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.9.tgz", - "integrity": "sha512-XMyVIFGomVCmCm92EvYlgq3zrC9K+J6r7IKl/rBJT2/xVYoRY6uM7jeB+Wxh7kXxnW9Dbqsr2yL3cx6wSD1sAg==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", + "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", "requires": { - "@babel/runtime": "^7.20.13", - "@mui/utils": "^5.11.9", + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.15.14", "prop-types": "^15.8.1" } }, "@mui/styled-engine": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.9.tgz", - "integrity": "sha512-bkh2CjHKOMy98HyOc8wQXEZvhOmDa/bhxMUekFX5IG0/w4f5HJ8R6+K6nakUUYNEgjOWPYzNPrvGB8EcGbhahQ==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", + "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", "requires": { - "@babel/runtime": "^7.20.13", - "@emotion/cache": "^11.10.5", - "csstype": "^3.1.1", + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1" } }, "@mui/system": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.9.tgz", - "integrity": "sha512-h6uarf+l3FO6l75Nf7yO+qDGrIoa1DM9nAMCUFZQsNCDKOInRzcptnm8M1w/Z3gVetfeeGoIGAYuYKbft6KZZA==", - "requires": { - "@babel/runtime": "^7.20.13", - "@mui/private-theming": "^5.11.9", - "@mui/styled-engine": "^5.11.9", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.9", - "clsx": "^1.2.1", - "csstype": "^3.1.1", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.14.tgz", + "integrity": "sha512-auXLXzUaCSSOLqJXmsAaq7P96VPRXg2Rrz6OHNV7lr+kB8lobUF+/N84Vd9C4G/wvCXYPs5TYuuGBRhcGbiBGg==", + "requires": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.15.14", + "@mui/styled-engine": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "clsx": "^2.1.0", + "csstype": "^3.1.3", "prop-types": "^15.8.1" } }, "@mui/types": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", - "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==", + "version": "7.2.14", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", + "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", "requires": {} }, "@mui/utils": { - "version": "5.11.9", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.9.tgz", - "integrity": "sha512-eOJaqzcEs4qEwolcvFAmXGpln+uvouvOS9FUX6Wkrte+4I8rZbjODOBDVNlK+V6/ziTfD4iNKC0G+KfOTApbqg==", + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", + "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", "requires": { - "@babel/runtime": "^7.20.13", - "@types/prop-types": "^15.7.5", - "@types/react-is": "^16.7.1 || ^17.0.0", + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" } @@ -9062,9 +9132,9 @@ "dev": true }, "@popperjs/core": { - "version": "2.11.6", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", - "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, "@remix-run/router": { "version": "1.3.2", @@ -9271,9 +9341,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "@types/qs": { "version": "6.9.7", @@ -9306,18 +9376,10 @@ "@types/react": "*" } }, - "@types/react-is": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", - "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", - "requires": { - "@types/react": "*" - } - }, "@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "requires": { "@types/react": "*" } @@ -10141,9 +10203,9 @@ } }, "clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==" }, "color-convert": { "version": "2.0.1", @@ -10340,9 +10402,9 @@ "dev": true }, "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "damerau-levenshtein": { "version": "1.0.8", @@ -13201,9 +13263,9 @@ } }, "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "regexp.prototype.flags": { "version": "1.4.3", diff --git a/ui/react-app/package.json b/ui/react-app/package.json index 13f57b0493..8297b980ba 100644 --- a/ui/react-app/package.json +++ b/ui/react-app/package.json @@ -12,7 +12,7 @@ "dependencies": { "@emotion/react": "^11.9.3", "@emotion/styled": "^11.9.3", - "@mui/material": "^5.10.14", + "@mui/material": "^5.15.14", "@tanstack/react-query": "^4.7.1", "mdi-material-ui": "^7.4.0", "react": "^18.0.0",