From 20c04c778b3cd0a1d1491b300f3eb50158461a55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:32:04 +0000 Subject: [PATCH 01/16] build(deps): bump k8s.io/apimachinery from 0.31.3 to 0.31.4 in /clients/ui/bff (#637) Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.31.3 to 0.31.4. - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.31.3...v0.31.4) --- updated-dependencies: - dependency-name: k8s.io/apimachinery dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- clients/ui/bff/go.mod | 2 +- clients/ui/bff/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clients/ui/bff/go.mod b/clients/ui/bff/go.mod index e0067787..58102e71 100644 --- a/clients/ui/bff/go.mod +++ b/clients/ui/bff/go.mod @@ -10,7 +10,7 @@ require ( github.com/onsi/gomega v1.35.1 github.com/stretchr/testify v1.9.0 k8s.io/api v0.31.2 - k8s.io/apimachinery v0.31.3 + k8s.io/apimachinery v0.31.4 k8s.io/client-go v0.31.2 sigs.k8s.io/controller-runtime v0.19.1 ) diff --git a/clients/ui/bff/go.sum b/clients/ui/bff/go.sum index 2adc9409..bc28ba1d 100644 --- a/clients/ui/bff/go.sum +++ b/clients/ui/bff/go.sum @@ -182,8 +182,8 @@ k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= -k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= -k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apimachinery v0.31.4 h1:8xjE2C4CzhYVm9DGf60yohpNUh5AEBnPxCryPBECmlM= +k8s.io/apimachinery v0.31.4/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= From 1449fb38e235c9a64606a54a53fac0ed3d8a83de Mon Sep 17 00:00:00 2001 From: Eder Ignatowicz Date: Wed, 11 Dec 2024 08:21:04 -0500 Subject: [PATCH 02/16] feat(bff): user info endpoint (#630) * feat(bff): user info endpoint Signed-off-by: Eder Ignatowicz * Update clients/ui/bff/README.md Co-authored-by: Griffin Sullivan <48397354+Griffin-Sullivan@users.noreply.github.com> Signed-off-by: Eder Ignatowicz --------- Signed-off-by: Eder Ignatowicz Co-authored-by: Griffin Sullivan <48397354+Griffin-Sullivan@users.noreply.github.com> --- clients/ui/bff/README.md | 5 + clients/ui/bff/internal/api/app.go | 2 + clients/ui/bff/internal/api/middleware.go | 6 + clients/ui/bff/internal/api/user_handler.go | 36 ++++++ .../ui/bff/internal/api/user_handler_test.go | 119 ++++++++++++++++++ clients/ui/bff/internal/integrations/k8s.go | 28 +++++ clients/ui/bff/internal/mocks/k8s_mock.go | 97 +++++++++++--- .../ui/bff/internal/mocks/k8s_mock_test.go | 25 +++- clients/ui/bff/internal/models/user.go | 6 + .../bff/internal/repositories/repositories.go | 2 + clients/ui/bff/internal/repositories/user.go | 28 +++++ 11 files changed, 333 insertions(+), 21 deletions(-) create mode 100644 clients/ui/bff/internal/api/user_handler.go create mode 100644 clients/ui/bff/internal/api/user_handler_test.go create mode 100644 clients/ui/bff/internal/models/user.go create mode 100644 clients/ui/bff/internal/repositories/user.go diff --git a/clients/ui/bff/README.md b/clients/ui/bff/README.md index a9e0d08f..aa92da5b 100644 --- a/clients/ui/bff/README.md +++ b/clients/ui/bff/README.md @@ -57,6 +57,7 @@ make docker-build | URL Pattern | Handler | Action | |----------------------------------------------------------------------------------------------|----------------------------------------------|-------------------------------------------------------------| | GET /v1/healthcheck | HealthcheckHandler | Show application information. | +| GET /v1/user | UserHandler | Show "kubeflow-user-id" from header information. | | GET /v1/model_registry | ModelRegistryHandler | Get all model registries, | | GET /v1/model_registry/{model_registry_id}/registered_models | GetAllRegisteredModelsHandler | Gets a list of all RegisteredModel entities. | | POST /v1/model_registry/{model_registry_id}/registered_models | CreateRegisteredModelHandler | Create a RegisteredModel entity. | @@ -78,6 +79,10 @@ You will need to inject your requests with a kubeflow-userid header for authoriz curl -i -H "kubeflow-userid: user@example.com" localhost:4000/api/v1/healthcheck ``` ``` +# GET /v1/user +curl -i -H "kubeflow-userid: user@example.com" localhost:4000/api/v1/user +``` +``` # GET /v1/model_registry curl -i -H "kubeflow-userid: user@example.com" localhost:4000/api/v1/model_registry ``` diff --git a/clients/ui/bff/internal/api/app.go b/clients/ui/bff/internal/api/app.go index 916ad348..c7047f29 100644 --- a/clients/ui/bff/internal/api/app.go +++ b/clients/ui/bff/internal/api/app.go @@ -21,6 +21,7 @@ const ( ModelVersionId = "model_version_id" ModelArtifactId = "model_artifact_id" HealthCheckPath = PathPrefix + "/healthcheck" + UserPath = PathPrefix + "/user" ModelRegistryListPath = PathPrefix + "/model_registry" ModelRegistryPath = ModelRegistryListPath + "/:" + ModelRegistryId RegisteredModelListPath = ModelRegistryPath + "/registered_models" @@ -103,6 +104,7 @@ func (app *App) Routes() http.Handler { router.POST(ModelVersionArtifactListPath, app.AttachRESTClient(app.CreateModelArtifactByModelVersionHandler)) // Kubernetes client routes + router.GET(UserPath, app.UserHandler) router.GET(ModelRegistryListPath, app.ModelRegistryHandler) router.PATCH(ModelRegistryPath, app.AttachRESTClient(app.UpdateModelVersionHandler)) diff --git a/clients/ui/bff/internal/api/middleware.go b/clients/ui/bff/internal/api/middleware.go index 6a16fcf8..02275b5f 100644 --- a/clients/ui/bff/internal/api/middleware.go +++ b/clients/ui/bff/internal/api/middleware.go @@ -83,6 +83,12 @@ func (app *App) RequireAccessControl(next http.Handler) http.Handler { return } + // Skip SAR for user info + if r.URL.Path == UserPath { + next.ServeHTTP(w, r) + return + } + user := r.Header.Get(kubeflowUserId) if user == "" { app.forbiddenResponse(w, r, "missing kubeflow-userid header") diff --git a/clients/ui/bff/internal/api/user_handler.go b/clients/ui/bff/internal/api/user_handler.go new file mode 100644 index 00000000..a5bcd264 --- /dev/null +++ b/clients/ui/bff/internal/api/user_handler.go @@ -0,0 +1,36 @@ +package api + +import ( + "errors" + "github.com/julienschmidt/httprouter" + "github.com/kubeflow/model-registry/ui/bff/internal/models" + "net/http" +) + +type UserEnvelope Envelope[*models.User, None] + +func (app *App) UserHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + + userHeader := r.Header.Get(kubeflowUserId) + if userHeader == "" { + app.serverErrorResponse(w, r, errors.New("kubeflow-userid not present on header")) + return + } + + user, err := app.repositories.User.GetUser(app.kubernetesClient, userHeader) + if err != nil { + app.serverErrorResponse(w, r, err) + return + } + + userRes := UserEnvelope{ + Data: user, + } + + err = app.WriteJSON(w, http.StatusOK, userRes, nil) + + if err != nil { + app.serverErrorResponse(w, r, err) + } + +} diff --git a/clients/ui/bff/internal/api/user_handler_test.go b/clients/ui/bff/internal/api/user_handler_test.go new file mode 100644 index 00000000..0accd253 --- /dev/null +++ b/clients/ui/bff/internal/api/user_handler_test.go @@ -0,0 +1,119 @@ +package api + +import ( + "encoding/json" + "io" + "net/http" + "net/http/httptest" + + "github.com/kubeflow/model-registry/ui/bff/internal/repositories" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +const ( + KubeflowUserIDHeaderValue = "user@example.com" + DoraNonAdminUser = "doraNonAdmin@example.com" +) + +var _ = Describe("TestUserHandler", func() { + Context("fetching user details", Ordered, func() { + var testApp App + + BeforeAll(func() { + By("creating the test app") + testApp = App{ + kubernetesClient: k8sClient, + repositories: repositories.NewRepositories(mockMRClient), + logger: logger, + } + }) + + It("should show that KubeflowUserIDHeaderValue (user@example.com) is a cluster-admin", func() { + By("creating the http request") + req, err := http.NewRequest(http.MethodGet, UserPath, nil) + Expect(err).NotTo(HaveOccurred()) + + req.Header.Set(kubeflowUserId, KubeflowUserIDHeaderValue) + + By("creating the http test infrastructure") + rr := httptest.NewRecorder() + + By("invoking the UserHandler") + testApp.UserHandler(rr, req, nil) + rs := rr.Result() + defer rs.Body.Close() + body, err := io.ReadAll(rs.Body) + Expect(err).NotTo(HaveOccurred()) + + By("unmarshalling the user response") + var actual UserEnvelope + err = json.Unmarshal(body, &actual) + Expect(err).NotTo(HaveOccurred()) + Expect(rr.Code).To(Equal(http.StatusOK)) + + By("checking that the user is cluster-admin") + Expect(actual.Data.UserID).To(Equal(KubeflowUserIDHeaderValue)) + Expect(actual.Data.ClusterAdmin).To(BeTrue(), "Expected this user to be cluster-admin") + }) + + It("should show that DoraNonAdminUser (doraNonAdmin@example.com) is not a cluster-admin", func() { + By("creating the http request") + req, err := http.NewRequest(http.MethodGet, UserPath, nil) + Expect(err).NotTo(HaveOccurred()) + + req.Header.Set(kubeflowUserId, DoraNonAdminUser) + + By("creating the http test infrastructure") + rr := httptest.NewRecorder() + + By("invoking the UserHandler") + testApp.UserHandler(rr, req, nil) + rs := rr.Result() + defer rs.Body.Close() + body, err := io.ReadAll(rs.Body) + Expect(err).NotTo(HaveOccurred()) + + By("unmarshalling the user response") + var actual UserEnvelope + err = json.Unmarshal(body, &actual) + Expect(err).NotTo(HaveOccurred()) + Expect(rr.Code).To(Equal(http.StatusOK)) + + By("checking that the user is not cluster-admin") + Expect(actual.Data.UserID).To(Equal(DoraNonAdminUser)) + Expect(actual.Data.ClusterAdmin).To(BeFalse(), "Expected this user to not be cluster-admin") + }) + + It("should show that a random non-existent user is not a cluster-admin", func() { + randomUser := "bellaUser@example.com" + + By("creating the http request") + req, err := http.NewRequest(http.MethodGet, UserPath, nil) + Expect(err).NotTo(HaveOccurred()) + + req.Header.Set(kubeflowUserId, randomUser) + + By("creating the http test infrastructure") + rr := httptest.NewRecorder() + + By("invoking the UserHandler") + testApp.UserHandler(rr, req, nil) + rs := rr.Result() + defer rs.Body.Close() + body, err := io.ReadAll(rs.Body) + Expect(err).NotTo(HaveOccurred()) + + By("unmarshalling the user response") + var actual UserEnvelope + err = json.Unmarshal(body, &actual) + Expect(err).NotTo(HaveOccurred()) + Expect(rr.Code).To(Equal(http.StatusOK)) + + By("checking that the user is not cluster-admin") + Expect(actual.Data.UserID).To(Equal(randomUser)) + Expect(actual.Data.ClusterAdmin).To(BeFalse(), "Expected this user to not be cluster-admin") + }) + }) + +}) diff --git a/clients/ui/bff/internal/integrations/k8s.go b/clients/ui/bff/internal/integrations/k8s.go index 98a31984..5e3943be 100644 --- a/clients/ui/bff/internal/integrations/k8s.go +++ b/clients/ui/bff/internal/integrations/k8s.go @@ -6,6 +6,7 @@ import ( helper "github.com/kubeflow/model-registry/ui/bff/internal/helpers" authv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" @@ -27,6 +28,7 @@ type KubernetesClientInterface interface { Shutdown(ctx context.Context, logger *slog.Logger) error IsInCluster() bool PerformSAR(user string) (bool, error) + IsClusterAdmin(user string) (bool, error) } type ServiceDetails struct { @@ -286,3 +288,29 @@ func (kc *KubernetesClient) PerformSAR(user string) (bool, error) { return true, nil } + +func (kc *KubernetesClient) IsClusterAdmin(user string) (bool, error) { + //using a context here, because checking ClusterRoleBindings could be expensive in large clusters + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + clusterRoleBindings := &rbacv1.ClusterRoleBindingList{} + err := kc.ControllerRuntimeClient.List(ctx, clusterRoleBindings) + if err != nil { + return false, fmt.Errorf("failed to list ClusterRoleBindings: %w", err) + } + + for _, crb := range clusterRoleBindings.Items { + if crb.RoleRef.Name != "cluster-admin" { + continue + } + for _, subject := range crb.Subjects { + + if subject.Kind == "User" && subject.Name == user { + return true, nil + } + } + } + + return false, nil +} diff --git a/clients/ui/bff/internal/mocks/k8s_mock.go b/clients/ui/bff/internal/mocks/k8s_mock.go index 0a6f8593..7d2e86e8 100644 --- a/clients/ui/bff/internal/mocks/k8s_mock.go +++ b/clients/ui/bff/internal/mocks/k8s_mock.go @@ -17,7 +17,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/envtest" ) -const KubeflowUserIDHeaderValue = "user@example.com" +const ( + KubeflowUserIDHeaderValue = "user@example.com" + DoraNonAdminUser = "doraNonAdmin@example.com" +) type KubernetesClientMock struct { *k8s.KubernetesClient @@ -114,22 +117,37 @@ func getProjectRoot() (string, error) { } func setupMock(mockK8sClient client.Client, ctx context.Context) error { - err := createService(mockK8sClient, ctx, "model-registry", "default", "Model Registry", "Model Registry Description", "10.0.0.10") + err := createNamespace(mockK8sClient, ctx, "kubeflow") + if err != nil { + return err + } + + err = createNamespace(mockK8sClient, ctx, "dora-namespace") + if err != nil { + return err + } + + err = createService(mockK8sClient, ctx, "model-registry", "kubeflow", "Model Registry", "Model Registry Description", "10.0.0.10") if err != nil { return err } - err = createService(mockK8sClient, ctx, "model-registry-dora", "default", "Model Registry Dora", "Model Registry Dora description", "10.0.0.11") + err = createService(mockK8sClient, ctx, "model-registry-dora", "dora-namespace", "Model Registry Dora", "Model Registry Dora description", "10.0.0.11") if err != nil { return err } - err = createService(mockK8sClient, ctx, "model-registry-bella", "default", "Model Registry Bella", "Model Registry Bella description", "10.0.0.12") + err = createService(mockK8sClient, ctx, "model-registry-bella", "kubeflow", "Model Registry Bella", "Model Registry Bella description", "10.0.0.12") if err != nil { return err } - err = createRBAC(mockK8sClient, ctx, KubeflowUserIDHeaderValue) + err = createClusterAdminRBAC(mockK8sClient, ctx, KubeflowUserIDHeaderValue) + if err != nil { + return fmt.Errorf("failed to create cluster admin RBAC: %w", err) + } + + err = createNamespaceRestrictedRBAC(mockK8sClient, ctx, DoraNonAdminUser, "dora-namespace") if err != nil { - return fmt.Errorf("failed to create RBAC for KubeflowUserIDHeaderValue: %w", err) + return fmt.Errorf("failed to create namespace-restricted RBAC: %w", err) } return nil @@ -224,28 +242,71 @@ func createService(k8sClient client.Client, ctx context.Context, name string, na return nil } -func createRBAC(k8sClient client.Client, ctx context.Context, username string) error { - clusterRole := &rbacv1.ClusterRole{ +func createNamespace(k8sClient client.Client, ctx context.Context, namespace string) error { + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: namespace, + }, + } + + err := k8sClient.Create(ctx, ns) + if err != nil { + return fmt.Errorf("failed to create namespace %s: %w", namespace, err) + } + + return nil +} + +func createClusterAdminRBAC(k8sClient client.Client, ctx context.Context, username string) error { + clusterRoleBinding := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: "service-access-role", + Name: fmt.Sprintf("cluster-admin-binding-%s", username), + }, + Subjects: []rbacv1.Subject{ + { + Kind: "User", + Name: username, + }, + }, + RoleRef: rbacv1.RoleRef{ + Kind: "ClusterRole", + Name: "cluster-admin", + APIGroup: "rbac.authorization.k8s.io", + }, + } + + err := k8sClient.Create(ctx, clusterRoleBinding) + if err != nil { + return fmt.Errorf("failed to create cluster admin ClusterRoleBinding: %w", err) + } + + return nil +} + +func createNamespaceRestrictedRBAC(k8sClient client.Client, ctx context.Context, username, namespace string) error { + role := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "namespace-restricted-role", + Namespace: namespace, }, Rules: []rbacv1.PolicyRule{ { - APIGroups: []string{""}, // Core API group + APIGroups: []string{""}, Resources: []string{"services"}, Verbs: []string{"get", "list"}, }, }, } - err := k8sClient.Create(ctx, clusterRole) + err := k8sClient.Create(ctx, role) if err != nil { - return fmt.Errorf("failed to create ClusterRole: %w", err) + return fmt.Errorf("failed to create Role: %w", err) } - clusterRoleBinding := &rbacv1.ClusterRoleBinding{ + roleBinding := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: "service-access-binding", + Name: "namespace-restricted-binding", + Namespace: namespace, }, Subjects: []rbacv1.Subject{ { @@ -254,15 +315,15 @@ func createRBAC(k8sClient client.Client, ctx context.Context, username string) e }, }, RoleRef: rbacv1.RoleRef{ - Kind: "ClusterRole", - Name: "service-access-role", + Kind: "Role", + Name: "namespace-restricted-role", APIGroup: "rbac.authorization.k8s.io", }, } - err = k8sClient.Create(ctx, clusterRoleBinding) + err = k8sClient.Create(ctx, roleBinding) if err != nil { - return fmt.Errorf("failed to create ClusterRoleBinding: %w", err) + return fmt.Errorf("failed to create RoleBinding: %w", err) } return nil diff --git a/clients/ui/bff/internal/mocks/k8s_mock_test.go b/clients/ui/bff/internal/mocks/k8s_mock_test.go index 5fce6bf7..d77c658b 100644 --- a/clients/ui/bff/internal/mocks/k8s_mock_test.go +++ b/clients/ui/bff/internal/mocks/k8s_mock_test.go @@ -53,9 +53,8 @@ var _ = Describe("Kubernetes ControllerRuntimeClient Test", func() { Expect(err).NotTo(HaveOccurred(), "Failed to create HTTP request") By("checking that service details are correct") - Expect(services[0]).To(Equal("model-registry")) - Expect(services[1]).To(Equal("model-registry-bella")) - Expect(services[2]).To(Equal("model-registry-dora")) + Expect(services).To(ConsistOf("model-registry", "model-registry-bella", "model-registry-dora")) + }) }) @@ -80,3 +79,23 @@ var _ = Describe("KubernetesNativeClient SAR Test", func() { }) }) + +var _ = Describe("KubernetesClient isClusterAdmin Test", func() { + Context("checking cluster admin status", func() { + It("should confirm that user@example.com(KubeflowUserIDHeaderValue) is a cluster-admin", func() { + isAdmin, err := k8sClient.IsClusterAdmin(KubeflowUserIDHeaderValue) + Expect(err).NotTo(HaveOccurred()) + Expect(isAdmin).To(BeTrue()) + }) + It("should confirm that doraNonAdmin@example.com(DoraNonAdminUser) is a not cluster-admin", func() { + isAdmin, err := k8sClient.IsClusterAdmin(DoraNonAdminUser) + Expect(err).NotTo(HaveOccurred()) + Expect(isAdmin).To(BeFalse()) + }) + It("should confirm that non existent user is not a cluster-admin", func() { + isAdmin, err := k8sClient.IsClusterAdmin("bella@non-existent.com") + Expect(err).NotTo(HaveOccurred()) + Expect(isAdmin).To(BeFalse()) + }) + }) +}) diff --git a/clients/ui/bff/internal/models/user.go b/clients/ui/bff/internal/models/user.go new file mode 100644 index 00000000..c719bced --- /dev/null +++ b/clients/ui/bff/internal/models/user.go @@ -0,0 +1,6 @@ +package models + +type User struct { + UserID string `json:"user-id"` + ClusterAdmin bool `json:"cluster-admin"` +} diff --git a/clients/ui/bff/internal/repositories/repositories.go b/clients/ui/bff/internal/repositories/repositories.go index e0e660d6..5efa9b84 100644 --- a/clients/ui/bff/internal/repositories/repositories.go +++ b/clients/ui/bff/internal/repositories/repositories.go @@ -5,6 +5,7 @@ type Repositories struct { HealthCheck *HealthCheckRepository ModelRegistry *ModelRegistryRepository ModelRegistryClient ModelRegistryClientInterface + User *UserRepository } func NewRepositories(modelRegistryClient ModelRegistryClientInterface) *Repositories { @@ -12,5 +13,6 @@ func NewRepositories(modelRegistryClient ModelRegistryClientInterface) *Reposito HealthCheck: NewHealthCheckRepository(), ModelRegistry: NewModelRegistryRepository(), ModelRegistryClient: modelRegistryClient, + User: NewUserRepository(), } } diff --git a/clients/ui/bff/internal/repositories/user.go b/clients/ui/bff/internal/repositories/user.go new file mode 100644 index 00000000..77a9a42e --- /dev/null +++ b/clients/ui/bff/internal/repositories/user.go @@ -0,0 +1,28 @@ +package repositories + +import ( + "fmt" + k8s "github.com/kubeflow/model-registry/ui/bff/internal/integrations" + "github.com/kubeflow/model-registry/ui/bff/internal/models" +) + +type UserRepository struct{} + +func NewUserRepository() *UserRepository { + return &UserRepository{} +} + +func (r *UserRepository) GetUser(client k8s.KubernetesClientInterface, user string) (*models.User, error) { + + isAdmin, err := client.IsClusterAdmin(user) + if err != nil { + return nil, fmt.Errorf("error getting user info: %w", err) + } + + var res = models.User{ + UserID: user, + ClusterAdmin: isAdmin, + } + + return &res, nil +} From 6fe5f3566eac2572227333e89f871a43a631dce4 Mon Sep 17 00:00:00 2001 From: Eder Ignatowicz Date: Wed, 11 Dec 2024 08:30:04 -0500 Subject: [PATCH 03/16] bump @typescript-eslint/parser and @typescript-eslint/eslint-plugin from 8.13.0 to 8.17.0 in /clients/ui/frontend (#631) Signed-off-by: Eder Ignatowicz --- clients/ui/frontend/package-lock.json | 139 +++++++++--------- clients/ui/frontend/package.json | 4 +- .../DashboardDescriptionListGroup.tsx | 2 +- 3 files changed, 74 insertions(+), 71 deletions(-) diff --git a/clients/ui/frontend/package-lock.json b/clients/ui/frontend/package-lock.json index aad63a24..643bac7b 100644 --- a/clients/ui/frontend/package-lock.json +++ b/clients/ui/frontend/package-lock.json @@ -93,8 +93,8 @@ "node": ">=20.0.0" }, "optionalDependencies": { - "@typescript-eslint/eslint-plugin": "^8.8.1", - "@typescript-eslint/parser": "^8.12.2", + "@typescript-eslint/eslint-plugin": "^8.17.0", + "@typescript-eslint/parser": "^8.17.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-node": "^0.3.7", @@ -4647,17 +4647,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz", - "integrity": "sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.0.tgz", + "integrity": "sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==", "license": "MIT", "optional": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/type-utils": "8.13.0", - "@typescript-eslint/utils": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/type-utils": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4672,25 +4672,21 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.13.0.tgz", - "integrity": "sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==", - "license": "BSD-2-Clause", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.0.tgz", + "integrity": "sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==", + "license": "MITClause", "optional": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "debug": "^4.3.4" }, "engines": { @@ -4701,23 +4697,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz", - "integrity": "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", + "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", "license": "MIT", "optional": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0" + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4728,14 +4720,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz", - "integrity": "sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.0.tgz", + "integrity": "sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==", "license": "MIT", "optional": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/utils": "8.13.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/utils": "8.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -4746,16 +4738,15 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.13.0.tgz", - "integrity": "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", + "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", "license": "MIT", "optional": true, "engines": { @@ -4767,14 +4758,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz", - "integrity": "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==", - "license": "BSD-2-Clause", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", + "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", + "license": "MIT", "optional": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4789,10 +4780,8 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { @@ -4809,16 +4798,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.13.0.tgz", - "integrity": "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.0.tgz", + "integrity": "sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==", "license": "MIT", "optional": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0" + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4828,18 +4817,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz", - "integrity": "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", + "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", "license": "MIT", "optional": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.18.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4849,6 +4839,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", diff --git a/clients/ui/frontend/package.json b/clients/ui/frontend/package.json index 013c75e3..204e5df2 100644 --- a/clients/ui/frontend/package.json +++ b/clients/ui/frontend/package.json @@ -112,8 +112,8 @@ "classnames": "^2.2.6" }, "optionalDependencies": { - "@typescript-eslint/eslint-plugin": "^8.8.1", - "@typescript-eslint/parser": "^8.12.2", + "@typescript-eslint/eslint-plugin": "^8.17.0", + "@typescript-eslint/parser": "^8.17.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-node": "^0.3.7", diff --git a/clients/ui/frontend/src/shared/components/DashboardDescriptionListGroup.tsx b/clients/ui/frontend/src/shared/components/DashboardDescriptionListGroup.tsx index 7a65b61c..a9ab8b55 100644 --- a/clients/ui/frontend/src/shared/components/DashboardDescriptionListGroup.tsx +++ b/clients/ui/frontend/src/shared/components/DashboardDescriptionListGroup.tsx @@ -26,7 +26,7 @@ type EditableProps = { }; export type DashboardDescriptionListGroupProps = { - title: React.ReactNode; + title: string; tooltip?: React.ReactNode; action?: React.ReactNode; isEmpty?: boolean; From b04676475ae707dadbec64b65831a3f3211fcfeb Mon Sep 17 00:00:00 2001 From: Eder Ignatowicz Date: Wed, 11 Dec 2024 08:32:03 -0500 Subject: [PATCH 04/16] build(deps-dev): bump react-router-dom and react-router from 6.28.0 to 7.0.2 in /clients/ui/frontend (#632) Signed-off-by: Eder Ignatowicz --- clients/ui/frontend/package-lock.json | 77 ++++++++++++++++++--------- clients/ui/frontend/package.json | 4 +- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/clients/ui/frontend/package-lock.json b/clients/ui/frontend/package-lock.json index 643bac7b..193f8d12 100644 --- a/clients/ui/frontend/package-lock.json +++ b/clients/ui/frontend/package-lock.json @@ -22,7 +22,7 @@ "npm-run-all": "^4.1.5", "react": "^18", "react-dom": "^18", - "react-router": "^6.26.2", + "react-router": "^7.0.2", "sass": "^1.78.0", "showdown": "^2.1.0" }, @@ -69,7 +69,7 @@ "prettier": "^3.3.3", "prop-types": "^15.8.1", "raw-loader": "^4.0.2", - "react-router-dom": "^6.28.0", + "react-router-dom": "^7.0.2", "regenerator-runtime": "^0.14.1", "rimraf": "^6.0.1", "sass-loader": "^16.0.1", @@ -3851,14 +3851,6 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@remix-run/router": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", - "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -4180,6 +4172,12 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/dompurify": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", @@ -16915,34 +16913,53 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.0.tgz", - "integrity": "sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.0.2.tgz", + "integrity": "sha512-m5AcPfTRUcjwmhBzOJGEl6Y7+Crqyju0+TgTQxoS4SO+BkWbhOrcfZNq6wSWdl2BBbJbsAoBUb8ZacOFT+/JlA==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.21.0" + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, "node_modules/react-router-dom": { - "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.0.tgz", - "integrity": "sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.0.2.tgz", + "integrity": "sha512-VJOQ+CDWFDGaWdrG12Nl+d7yHtLaurNgAQZVgaIy7/Xd+DojgmYLosFfZdGz1wpxmjJIAkAMVTKWcvkx1oggAw==", "dev": true, + "license": "MIT", "dependencies": { - "@remix-run/router": "1.21.0", - "react-router": "6.28.0" + "react-router": "7.0.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" } }, "node_modules/react-transition-group": { @@ -18101,6 +18118,12 @@ "dev": true, "license": "ISC" }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -19644,6 +19667,12 @@ "node": "*" } }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", diff --git a/clients/ui/frontend/package.json b/clients/ui/frontend/package.json index 204e5df2..0a785099 100644 --- a/clients/ui/frontend/package.json +++ b/clients/ui/frontend/package.json @@ -73,7 +73,7 @@ "prettier": "^3.3.3", "prop-types": "^15.8.1", "raw-loader": "^4.0.2", - "react-router-dom": "^6.28.0", + "react-router-dom": "^7.0.2", "regenerator-runtime": "^0.14.1", "rimraf": "^6.0.1", "sass-loader": "^16.0.1", @@ -105,7 +105,7 @@ "npm-run-all": "^4.1.5", "react": "^18", "react-dom": "^18", - "react-router": "^6.26.2", + "react-router": "^7.0.2", "sass": "^1.78.0", "dompurify": "^3.2.0", "showdown": "^2.1.0", From e599cda999be5526a8d7ae8d7ea215543dee865c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:43:04 +0000 Subject: [PATCH 05/16] build(deps-dev): bump typescript from 5.6.3 to 5.7.2 in /clients/ui/frontend (#638) Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.6.3 to 5.7.2. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.6.3...v5.7.2) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- clients/ui/frontend/package-lock.json | 8 ++++---- clients/ui/frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clients/ui/frontend/package-lock.json b/clients/ui/frontend/package-lock.json index 193f8d12..ee0bf564 100644 --- a/clients/ui/frontend/package-lock.json +++ b/clients/ui/frontend/package-lock.json @@ -81,7 +81,7 @@ "ts-loader": "^9.5.1", "tsconfig-paths-webpack-plugin": "^4.1.0", "tslib": "^2.7.0", - "typescript": "^5.6.3", + "typescript": "^5.7.2", "url-loader": "^4.1.1", "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.2", @@ -19814,9 +19814,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "devOptional": true, "license": "Apache-2.0", "bin": { diff --git a/clients/ui/frontend/package.json b/clients/ui/frontend/package.json index 0a785099..510d3970 100644 --- a/clients/ui/frontend/package.json +++ b/clients/ui/frontend/package.json @@ -85,7 +85,7 @@ "ts-loader": "^9.5.1", "tsconfig-paths-webpack-plugin": "^4.1.0", "tslib": "^2.7.0", - "typescript": "^5.6.3", + "typescript": "^5.7.2", "url-loader": "^4.1.1", "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.2", From 2fb4d26eafd1017f834202ec29d27dd4883d21f1 Mon Sep 17 00:00:00 2001 From: Lucas Fernandez Date: Fri, 13 Dec 2024 15:20:06 +0100 Subject: [PATCH 06/16] Improve username logic and add navbar elements (#641) * Enable kubeflow user id header from endpoint Signed-off-by: lucferbux * Add fake namespace selector and user in navbar Signed-off-by: lucferbux * Handle user config Signed-off-by: lucferbux * Add user endpoint Signed-off-by: lucferbux * Fix tests Signed-off-by: lucferbux --------- Signed-off-by: lucferbux --- clients/ui/api/openapi/mod-arch.yaml | 34 ++++++- .../ui/bff/internal/models/health_check.go | 2 +- clients/ui/bff/internal/models/user.go | 4 +- .../src/__mocks__/mockUserSettings.ts | 14 +++ .../cypress/cypress/support/commands/api.ts | 6 ++ .../__tests__/cypress/cypress/support/e2e.ts | 12 +++ clients/ui/frontend/src/app/App.tsx | 36 +++++--- clients/ui/frontend/src/app/AppRoutes.tsx | 20 ++-- clients/ui/frontend/src/app/NavBar.tsx | 91 +++++++++++++++++++ .../ui/frontend/src/shared/api/apiUtils.ts | 24 +++-- clients/ui/frontend/src/shared/api/k8s.ts | 13 +++ clients/ui/frontend/src/shared/api/types.ts | 1 + .../frontend/src/shared/hooks/useSettings.tsx | 21 ++--- .../frontend/src/shared/style/MUI-theme.scss | 3 +- clients/ui/frontend/src/shared/types.ts | 5 +- .../ui/frontend/src/shared/utilities/const.ts | 3 +- 16 files changed, 223 insertions(+), 66 deletions(-) create mode 100644 clients/ui/frontend/src/__mocks__/mockUserSettings.ts create mode 100644 clients/ui/frontend/src/app/NavBar.tsx diff --git a/clients/ui/api/openapi/mod-arch.yaml b/clients/ui/api/openapi/mod-arch.yaml index d1749468..931e7cc0 100644 --- a/clients/ui/api/openapi/mod-arch.yaml +++ b/clients/ui/api/openapi/mod-arch.yaml @@ -25,13 +25,15 @@ paths: operationId: healthcheck summary: HealthCheck description: HealthCheck endpoint. - /api/v1/config: - summary: Path used to manage Configuration information regarding the UI. + /api/v1/user: + summary: Path used to Retrieve a user based on the header. description: >- The REST endpoint/path used pass all the config information needed for the UI. get: tags: - K8SOperation + parameters: + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/ConfigResponse" @@ -49,6 +51,8 @@ paths: get: tags: - K8SOperation + parameters: + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/ModelRegistryRespone" @@ -68,6 +72,7 @@ paths: - ModelRegistryService parameters: - $ref: "#/components/parameters/modelRegistryName" + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/ModelVersionResponse" @@ -112,6 +117,7 @@ paths: description: Updates an existing `ModelVersion`. parameters: - $ref: "#/components/parameters/modelRegistryName" + - $ref: "#/components/parameters/kubeflowUserId" - name: modelversionId description: A unique identifier for a `ModelVersion`. schema: @@ -131,6 +137,7 @@ paths: - $ref: "#/components/parameters/orderBy" - $ref: "#/components/parameters/sortOrder" - $ref: "#/components/parameters/nextPageToken" + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/RegisteredModelListResponse" @@ -159,6 +166,7 @@ paths: - ModelRegistryService parameters: - $ref: "#/components/parameters/modelRegistryName" + - $ref: "#/components/parameters/kubeflowUserId" responses: "201": $ref: "#/components/responses/RegisteredModelResponse" @@ -180,6 +188,7 @@ paths: - ModelRegistryService parameters: - $ref: "#/components/parameters/modelRegistryName" + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/RegisteredModelResponse" @@ -224,6 +233,7 @@ paths: description: Updates an existing `RegisteredModel`. parameters: - $ref: "#/components/parameters/modelRegistryName" + - $ref: "#/components/parameters/kubeflowUserId" - name: registeredmodelId description: A unique identifier for a `RegisteredModel`. schema: @@ -245,6 +255,7 @@ paths: - $ref: "#/components/parameters/orderBy" - $ref: "#/components/parameters/sortOrder" - $ref: "#/components/parameters/nextPageToken" + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/ArtifactListResponse" @@ -274,6 +285,7 @@ paths: - ModelRegistryService parameters: - $ref: "#/components/parameters/modelRegistryName" + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/ArtifactResponse" @@ -311,6 +323,7 @@ paths: - $ref: "#/components/parameters/orderBy" - $ref: "#/components/parameters/sortOrder" - $ref: "#/components/parameters/nextPageToken" + - $ref: "#/components/parameters/kubeflowUserId" responses: "200": $ref: "#/components/responses/ModelVersionListResponse" @@ -355,6 +368,7 @@ paths: description: Creates a new instance of a `ModelVersion`. parameters: - $ref: "#/components/parameters/modelRegistryName" + - $ref: "#/components/parameters/kubeflowUserId" - name: registeredmodelId description: A unique identifier for a `RegisteredModel`. schema: @@ -365,12 +379,16 @@ components: schemas: Config: required: - - username + - userId + - clusterAdmin type: object properties: - username: + userId: type: string - example: username-1 + example: user@example.com + clusterAdmin: + type: boolean + example: true ModelRegistry: required: - name @@ -1193,6 +1211,12 @@ components: $ref: "#/components/schemas/ServeModel" description: A response containing a `ServeModel` entity. parameters: + kubeflowUserId: + in: header + name: kubeflow-userid + schema: + type: string + required: true modelRegistryName: name: modelRegistryName description: Name of the Model Registry selected. diff --git a/clients/ui/bff/internal/models/health_check.go b/clients/ui/bff/internal/models/health_check.go index cfee33ac..530fe1d4 100644 --- a/clients/ui/bff/internal/models/health_check.go +++ b/clients/ui/bff/internal/models/health_check.go @@ -7,5 +7,5 @@ type SystemInfo struct { type HealthCheckModel struct { Status string `json:"status"` SystemInfo SystemInfo `json:"system_info"` - UserID string `json:"user-id"` + UserID string `json:"userId"` } diff --git a/clients/ui/bff/internal/models/user.go b/clients/ui/bff/internal/models/user.go index c719bced..3cb49fa9 100644 --- a/clients/ui/bff/internal/models/user.go +++ b/clients/ui/bff/internal/models/user.go @@ -1,6 +1,6 @@ package models type User struct { - UserID string `json:"user-id"` - ClusterAdmin bool `json:"cluster-admin"` + UserID string `json:"userId"` + ClusterAdmin bool `json:"clusterAdmin"` } diff --git a/clients/ui/frontend/src/__mocks__/mockUserSettings.ts b/clients/ui/frontend/src/__mocks__/mockUserSettings.ts new file mode 100644 index 00000000..926b0c0f --- /dev/null +++ b/clients/ui/frontend/src/__mocks__/mockUserSettings.ts @@ -0,0 +1,14 @@ +import { UserSettings } from '~/shared/types'; + +type MockUserSettingsType = { + userId?: string; + clusterAdmin?: boolean; +}; + +export const mockUserSettings = ({ + userId = 'user@example.com', + clusterAdmin = true, +}: MockUserSettingsType): UserSettings => ({ + userId, + clusterAdmin, +}); diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts index 08423f51..54cbb27e 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts @@ -9,6 +9,7 @@ import type { RegisteredModel, RegisteredModelList, } from '~/app/types'; +import type { UserSettings } from '~/shared/types'; const MODEL_REGISTRY_API_VERSION = 'v1'; export { MODEL_REGISTRY_API_VERSION }; @@ -102,6 +103,11 @@ declare global { type: 'GET /api/:apiVersion/model_registry', options: { path: { apiVersion: string } }, response: ApiResponse, + ) => Cypress.Chainable) & + (( + type: 'GET /api/:apiVersion/user', + options: { path: { apiVersion: string } }, + response: ApiResponse, ) => Cypress.Chainable); } } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts index 4a6016e9..5b196a70 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts @@ -15,8 +15,10 @@ import chaiSubset from 'chai-subset'; import '@cypress/code-coverage/support'; +import { mockUserSettings } from '~/__mocks__/mockUserSettings'; import 'cypress-mochawesome-reporter/register'; import './commands'; +import { MODEL_REGISTRY_API_VERSION } from './commands/api'; chai.use(chaiSubset); @@ -28,5 +30,15 @@ beforeEach(() => { if (Cypress.env('MOCK')) { // fallback: return 404 for all api requests cy.intercept({ pathname: '/api/**' }, { statusCode: 404 }); + + cy.interceptApi( + 'GET /api/:apiVersion/user', + { + path: { + apiVersion: MODEL_REGISTRY_API_VERSION, + }, + }, + mockUserSettings({}), + ); } }); diff --git a/clients/ui/frontend/src/app/App.tsx b/clients/ui/frontend/src/app/App.tsx index d4c7f091..7510d690 100644 --- a/clients/ui/frontend/src/app/App.tsx +++ b/clients/ui/frontend/src/app/App.tsx @@ -5,9 +5,6 @@ import { Alert, Bullseye, Button, - Masthead, - MastheadContent, - MastheadMain, Page, PageSection, Spinner, @@ -16,11 +13,12 @@ import { } from '@patternfly/react-core'; import ToastNotifications from '~/shared/components/ToastNotifications'; import { useSettings } from '~/shared/hooks/useSettings'; -import { isMUITheme, Theme } from '~/shared/utilities/const'; +import { isMUITheme, Theme, USER_ID } from '~/shared/utilities/const'; import NavSidebar from './NavSidebar'; import AppRoutes from './AppRoutes'; import { AppContext } from './AppContext'; import { ModelRegistrySelectorContextProvider } from './context/ModelRegistrySelectorContext'; +import NavBar from './NavBar'; const App: React.FC = () => { const { @@ -30,6 +28,8 @@ const App: React.FC = () => { loadError: configError, } = useSettings(); + const username = userSettings?.userId; + React.useEffect(() => { // Apply the theme based on the value of STYLE_THEME if (isMUITheme()) { @@ -39,6 +39,16 @@ const App: React.FC = () => { } }, []); + React.useEffect(() => { + // Add the user to localStorage if in PoC + // TODO: [Env Handling] Just add this logic in PoC mode + if (username) { + localStorage.setItem(USER_ID, username); + } else { + localStorage.removeItem(USER_ID); + } + }, [username]); + const contextValue = React.useMemo( () => configSettings && userSettings @@ -82,15 +92,6 @@ const App: React.FC = () => { // Waiting on the API to finish const loading = !configLoaded || !userSettings || !configSettings || !contextValue; - const masthead = ( - - - - {/* TODO: [Auth-enablement] Add logout and user status once we enable itNavigates to register page from table toolbar */} - - - ); - return loading ? ( @@ -99,7 +100,14 @@ const App: React.FC = () => { { + //TODO: [Auth-enablement] Logout when auth is enabled + }} + /> + } isManagedSidebar sidebar={} > diff --git a/clients/ui/frontend/src/app/AppRoutes.tsx b/clients/ui/frontend/src/app/AppRoutes.tsx index 7dbf30b9..2e8b5f71 100644 --- a/clients/ui/frontend/src/app/AppRoutes.tsx +++ b/clients/ui/frontend/src/app/AppRoutes.tsx @@ -3,6 +3,7 @@ import { Navigate, Route, Routes } from 'react-router-dom'; import { NotFound } from './pages/notFound/NotFound'; import ModelRegistrySettingsRoutes from './pages/settings/ModelRegistrySettingsRoutes'; import ModelRegistryRoutes from './pages/modelRegistry/ModelRegistryRoutes'; +import { useAppContext } from './AppContext'; export const isNavDataGroup = (navItem: NavDataItem): navItem is NavDataGroup => 'children' in navItem; @@ -22,12 +23,9 @@ export type NavDataGroup = NavDataCommon & { type NavDataItem = NavDataHref | NavDataGroup; export const useAdminSettings = (): NavDataItem[] => { - // get auth access for example set admin as true - const isAdmin = true; //this should be a call to getting auth / role access + const { clusterAdmin } = useAppContext().user; - // TODO: [Auth-enablement] Remove the linter skip when we implement authentication - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (!isAdmin) { + if (!clusterAdmin) { return []; } @@ -48,20 +46,16 @@ export const useNavData = (): NavDataItem[] => [ ]; const AppRoutes: React.FC = () => { - const isAdmin = true; + const { clusterAdmin } = useAppContext().user; return ( } /> } /> } /> - { - // TODO: [Auth-enablement] Remove the linter skip when we implement authentication - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - isAdmin && ( - } /> - ) - } + {clusterAdmin && ( + } /> + )} ); }; diff --git a/clients/ui/frontend/src/app/NavBar.tsx b/clients/ui/frontend/src/app/NavBar.tsx new file mode 100644 index 00000000..62876c85 --- /dev/null +++ b/clients/ui/frontend/src/app/NavBar.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { + Dropdown, + DropdownItem, + DropdownList, + Masthead, + MastheadContent, + MastheadMain, + MenuToggle, + MenuToggleElement, + Toolbar, + ToolbarContent, + ToolbarGroup, + ToolbarItem, +} from '@patternfly/react-core'; +import { SimpleSelect, SimpleSelectOption } from '@patternfly/react-templates'; + +interface NavBarProps { + username?: string; + onLogout: () => void; +} + +const Options: SimpleSelectOption[] = [{ content: 'All Namespaces', value: 'All' }]; + +const NavBar: React.FC = ({ username, onLogout }) => { + const [selected, setSelected] = React.useState('All'); + const [userMenuOpen, setUserMenuOpen] = React.useState(false); + + const initialOptions = React.useMemo( + () => Options.map((o) => ({ ...o, selected: o.value === selected })), + [selected], + ); + + const handleLogout = () => { + setUserMenuOpen(false); + onLogout(); + }; + + const userMenuItems = [ + + Log out + , + ]; + + return ( + + + + + + + + setSelected(String(selection))} + /> + + + {username && ( + + + setUserMenuOpen(isOpen)} + toggle={(toggleRef: React.Ref) => ( + setUserMenuOpen(!userMenuOpen)} + isExpanded={userMenuOpen} + > + {username} + + )} + isOpen={userMenuOpen} + > + {userMenuItems} + + + + )} + + + + + ); +}; + +export default NavBar; diff --git a/clients/ui/frontend/src/shared/api/apiUtils.ts b/clients/ui/frontend/src/shared/api/apiUtils.ts index b5980718..f6cfb7fa 100644 --- a/clients/ui/frontend/src/shared/api/apiUtils.ts +++ b/clients/ui/frontend/src/shared/api/apiUtils.ts @@ -1,7 +1,7 @@ import { APIOptions } from '~/shared/api/types'; import { EitherOrNone } from '~/shared/typeHelpers'; import { ModelRegistryBody } from '~/app/types'; -import { USER_ACCESS_TOKEN } from '~/shared/utilities/const'; +import { USER_ID } from '~/shared/utilities/const'; export const mergeRequestInit = ( opts: APIOptions = {}, @@ -9,6 +9,10 @@ export const mergeRequestInit = ( ): RequestInit => ({ ...specificOpts, ...(opts.signal && { signal: opts.signal }), + headers: { + ...(opts.headers ?? {}), + ...(specificOpts.headers ?? {}), + }, }); type CallRestJSONOptions = { @@ -61,23 +65,17 @@ const callRestJSON = ( requestData = JSON.stringify(data); } - // Get from the browser storage the value from the key USER_ACCESS_TOKEN - // and set it as the value for the header key 'x-forwarded-access-token' - // This is a security measure to ensure that the user is authenticated - // before making any API calls. Local Storage is not secure, but it is - // enough for this PoC. - const token = localStorage.getItem(USER_ACCESS_TOKEN); - if (token) { - otherOptions.headers = { - ...otherOptions.headers, - [USER_ACCESS_TOKEN]: token, - }; - } + // Get from the browser storage the value from the key USER_ID + // and set it as a header value for the request. + // THIS IS ONLY INTENEDED FOR THE POC WHEN YOU CANNOT INJECT IT WITH A PROXY + // TODO: [Env Handling] Just add it when in PoC + const userID = localStorage.getItem(USER_ID); return fetch(`${host}${path}${searchParams ? `?${searchParams}` : ''}`, { ...otherOptions, headers: { ...otherOptions.headers, + ...(userID && { [USER_ID]: userID }), // TODO: [Env Handling] Just add it when in PoC ...(contentType && { 'Content-Type': contentType }), }, method, diff --git a/clients/ui/frontend/src/shared/api/k8s.ts b/clients/ui/frontend/src/shared/api/k8s.ts index 61b83d76..6c483eae 100644 --- a/clients/ui/frontend/src/shared/api/k8s.ts +++ b/clients/ui/frontend/src/shared/api/k8s.ts @@ -3,6 +3,7 @@ import { handleRestFailures } from '~/shared/api/errorUtils'; import { isModelRegistryResponse, restGET } from '~/shared/api/apiUtils'; import { ModelRegistry } from '~/app/types'; import { BFF_API_VERSION } from '~/app/const'; +import { UserSettings } from '~/shared/types'; export const getListModelRegistries = (hostPath: string) => @@ -15,3 +16,15 @@ export const getListModelRegistries = throw new Error('Invalid response format'); }, ); + +export const getUser = + (hostPath: string) => + (opts: APIOptions): Promise => + handleRestFailures(restGET(hostPath, `/api/${BFF_API_VERSION}/user`, {}, opts)).then( + (response) => { + if (isModelRegistryResponse(response)) { + return response.data; + } + throw new Error('Invalid response format'); + }, + ); diff --git a/clients/ui/frontend/src/shared/api/types.ts b/clients/ui/frontend/src/shared/api/types.ts index e7335512..bb0055bc 100644 --- a/clients/ui/frontend/src/shared/api/types.ts +++ b/clients/ui/frontend/src/shared/api/types.ts @@ -2,6 +2,7 @@ export type APIOptions = { dryRun?: boolean; signal?: AbortSignal; parseJSON?: boolean; + headers?: Record; }; export type APIError = { diff --git a/clients/ui/frontend/src/shared/hooks/useSettings.tsx b/clients/ui/frontend/src/shared/hooks/useSettings.tsx index 4aad461b..c5d45ee9 100644 --- a/clients/ui/frontend/src/shared/hooks/useSettings.tsx +++ b/clients/ui/frontend/src/shared/hooks/useSettings.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; -import { POLL_INTERVAL } from '~/shared/utilities/const'; +import { mockedUsername, POLL_INTERVAL, USER_ID } from '~/shared/utilities/const'; import { useDeepCompareMemoize } from '~/shared/utilities/useDeepCompareMemoize'; import { ConfigSettings, UserSettings } from '~/shared/types'; import useTimeBasedRefresh from '~/shared/hooks/useTimeBasedRefresh'; +import { getUser } from '~/shared/api/k8s'; export const useSettings = (): { configSettings: ConfigSettings | null; @@ -14,13 +15,17 @@ export const useSettings = (): { const [loadError, setLoadError] = React.useState(); const [config, setConfig] = React.useState(null); const [user, setUser] = React.useState(null); + const userSettings = React.useMemo(() => getUser(''), []); const setRefreshMarker = useTimeBasedRefresh(); React.useEffect(() => { let watchHandle: ReturnType; let cancelled = false; const watchConfig = () => { - Promise.all([fetchConfig(), fetchUser()]) + // TODO: [Env Handling] Add mocked mode for frontend in dev + // const headers = process.env.mocked === 'true' ? { [USER_ID]: mockedUsername } : undefined; + const headers = { [USER_ID]: mockedUsername }; + Promise.all([fetchConfig(), userSettings({ headers })]) .then(([fetchedConfig, fetchedUser]) => { if (cancelled) { return; @@ -53,7 +58,7 @@ export const useSettings = (): { cancelled = true; clearTimeout(watchHandle); }; - }, [setRefreshMarker]); + }, [setRefreshMarker, userSettings]); const retConfig = useDeepCompareMemoize(config); const retUser = useDeepCompareMemoize(user); @@ -62,7 +67,7 @@ export const useSettings = (): { }; // Mock a settings config call -// TODO: [Data Flow] replace with thea actual call once we have the endpoint +// TODO: [Data Flow] replace with the actual call once we have the endpoint export const fetchConfig = async (): Promise => ({ common: { featureFlags: { @@ -70,11 +75,3 @@ export const fetchConfig = async (): Promise => ({ }, }, }); - -// Mock a settings user call -// TODO: [Auth-enablement] replace with thea actual call once we have the endpoint -export const fetchUser = async (): Promise => ({ - username: 'admin', - isAdmin: true, - isAllowed: true, -}); diff --git a/clients/ui/frontend/src/shared/style/MUI-theme.scss b/clients/ui/frontend/src/shared/style/MUI-theme.scss index 8896ec5b..5596c0c2 100644 --- a/clients/ui/frontend/src/shared/style/MUI-theme.scss +++ b/clients/ui/frontend/src/shared/style/MUI-theme.scss @@ -747,6 +747,7 @@ --pf-v6-c-masthead--BackgroundColor: var(--mui-palette-common-white); box-shadow: var(--mui-shadows-1); min-height: var(--kf-central-app-bar-height); + margin-left: var(--kf-central-app-drawer-width); } .mui-theme .pf-v6-c-modal-box { @@ -795,7 +796,5 @@ } .mui-theme .pf-v6-c-page__main-container { - margin-left: var(--kf-central-app-drawer-width); /* Move content area to right of the sidebar */ margin-top: var(--kf-central-app-bar-height); /* Move content area below the app bar */ } - diff --git a/clients/ui/frontend/src/shared/types.ts b/clients/ui/frontend/src/shared/types.ts index 2b540f17..394c1720 100644 --- a/clients/ui/frontend/src/shared/types.ts +++ b/clients/ui/frontend/src/shared/types.ts @@ -2,9 +2,8 @@ import { ValueOf } from '~/shared/typeHelpers'; // TODO: [Data Flow] Get the status config params export type UserSettings = { - username: string; - isAdmin: boolean; - isAllowed: boolean; + userId: string; + clusterAdmin?: boolean; }; // TODO: [Data Flow] Add more config parameters diff --git a/clients/ui/frontend/src/shared/utilities/const.ts b/clients/ui/frontend/src/shared/utilities/const.ts index 359a6677..5cc0a8a8 100644 --- a/clients/ui/frontend/src/shared/utilities/const.ts +++ b/clients/ui/frontend/src/shared/utilities/const.ts @@ -11,6 +11,7 @@ export const isMUITheme = (): boolean => STYLE_THEME === Theme.MUI; export const STYLE_THEME = process.env.STYLE_THEME || Theme.MUI; -export const USER_ACCESS_TOKEN = 'x-forwarded-access-token'; +export const USER_ID = 'kubeflow-userid'; +export const mockedUsername = 'user@example.com'; export { POLL_INTERVAL }; From 8dd89afb4b1d5c1cbec301a9f685e1a7c002f43f Mon Sep 17 00:00:00 2001 From: Eder Ignatowicz Date: Fri, 13 Dec 2024 09:29:07 -0500 Subject: [PATCH 07/16] feat(bff): update bff service filtering to match model registry services by component: model-registry label (#633) Signed-off-by: Eder Ignatowicz --- clients/ui/bff/README.md | 35 ++++++ clients/ui/bff/internal/integrations/k8s.go | 124 +++++++++----------- clients/ui/bff/internal/mocks/k8s_mock.go | 21 +++- 3 files changed, 109 insertions(+), 71 deletions(-) diff --git a/clients/ui/bff/README.md b/clients/ui/bff/README.md index aa92da5b..fa2ad679 100644 --- a/clients/ui/bff/README.md +++ b/clients/ui/bff/README.md @@ -216,3 +216,38 @@ curl -i -H "kubeflow-userid: user@example.com" "http://localhost:4000/api/v1/mod # Get with a page size of 5, order by last update time in descending order. curl -i -H "kubeflow-userid: user@example.com" "http://localhost:4000/api/v1/model_registry/model-registry/registered_models?pageSize=5&orderBy=LAST_UPDATE_TIME&sortOrder=DESC" ``` + + +### FAQ + +#### 1. How do we filter model registry services from other Kubernetes services? + +We filter Model Registry services by using the Kubernetes label `component: model-registry. This label helps distinguish Model Registry services from other services in the cluster. + +For example, in our service manifest, the `component label is defined as follows: +```yaml +# ... +labels: + # ... + component: model-registry +#... +``` +You can view the complete Model Registry service manifest [here](https://github.com/kubeflow/model-registry/blob/main/manifests/kustomize/base/model-registry-service.yaml#L10). + +#### 2. What is the structure of the mock Kubernetes environment? + +The mock Kubernetes environment is activated when the environment variable `MOCK_K8S_CLIENT` is set to `true`. It is based on `env-test` and is designed to simulate a realistic Kubernetes setup for testing. The mock has the following characteristics: + +- **Namespaces**: + - `kubeflow` + - `dora-namespace` + +- **Users**: + - `user@example.com` (has `cluster-admin` privileges) + - `doraNonAdmin@example.com` (restricted to the `dora-namespace`) + +- **Services (Model Registries)**: + - `model-registry`: resides in the `kubeflow` namespace with the label `component: model-registry`. + - `model-registry-dora`: resides in the `dora-namespace` namespace with the label `component: model-registry`. + - `model-registry-bella`: resides in the `kubeflow` namespace with the label `component: model-registry`. + - `non-model-registry`: resides in the `kubeflow` namespace *without* the label `component: model-registry`. \ No newline at end of file diff --git a/clients/ui/bff/internal/integrations/k8s.go b/clients/ui/bff/internal/integrations/k8s.go index 5e3943be..8b6c7170 100644 --- a/clients/ui/bff/internal/integrations/k8s.go +++ b/clients/ui/bff/internal/integrations/k8s.go @@ -8,6 +8,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "log/slog" @@ -18,7 +19,7 @@ import ( "time" ) -const ComponentName = "model-registry-server" +const ComponentLabelValue = "model-registry" type KubernetesClientInterface interface { GetServiceNames() ([]string, error) @@ -150,42 +151,32 @@ func (kc *KubernetesClient) BearerToken() (string, error) { } func (kc *KubernetesClient) GetServiceNames() ([]string, error) { - //TODO (ederign) we should consider and rethinking listing all services on cluster - // what if we have thousand of those? - // we should consider label filtering for instance - - serviceList := &corev1.ServiceList{} - //TODO (ederign) review the context timeout - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second) - defer cancel() - - err := kc.ControllerRuntimeClient.List(ctx, serviceList, &client.ListOptions{}) + services, err := kc.GetServiceDetails() if err != nil { - return nil, fmt.Errorf("failed to list services: %w", err) - } - - var serviceNames []string - for _, service := range serviceList.Items { - if value, ok := service.Spec.Selector["component"]; ok && value == ComponentName { - serviceNames = append(serviceNames, service.Name) - } + return nil, err } - if len(serviceNames) == 0 { - return nil, fmt.Errorf("no services found with component: %s", ComponentName) + names := make([]string, 0, len(services)) + for _, svc := range services { + names = append(names, svc.Name) } - return serviceNames, nil + return names, nil } func (kc *KubernetesClient) GetServiceDetails() ([]ServiceDetails, error) { - //TODO (ederign) review the context timeout - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second) - defer cancel() // Ensure the context is canceled to free up resources + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() serviceList := &corev1.ServiceList{} - err := kc.ControllerRuntimeClient.List(ctx, serviceList, &client.ListOptions{}) + labelSelector := labels.SelectorFromSet(labels.Set{ + "component": ComponentLabelValue, + }) + + err := kc.ControllerRuntimeClient.List(ctx, serviceList, &client.ListOptions{ + LabelSelector: labelSelector, + }) if err != nil { return nil, fmt.Errorf("failed to list services: %w", err) } @@ -193,52 +184,51 @@ func (kc *KubernetesClient) GetServiceDetails() ([]ServiceDetails, error) { var services []ServiceDetails for _, service := range serviceList.Items { - if svcComponent, exists := service.Spec.Selector["component"]; exists && svcComponent == ComponentName { - var httpPort int32 - hasHTTPPort := false - for _, port := range service.Spec.Ports { - if port.Name == "http-api" { - httpPort = port.Port - hasHTTPPort = true - break - } - } - if !hasHTTPPort { - kc.Logger.Error("service missing HTTP port", "serviceName", service.Name) - continue - } - - if service.Spec.ClusterIP == "" { - kc.Logger.Error("service missing valid ClusterIP", "serviceName", service.Name) - continue + var httpPort int32 + hasHTTPPort := false + for _, port := range service.Spec.Ports { + if port.Name == "http-api" { + httpPort = port.Port + hasHTTPPort = true + break } + } + if !hasHTTPPort { + kc.Logger.Error("service missing HTTP port", "serviceName", service.Name) + continue + } - displayName := "" - description := "" + if service.Spec.ClusterIP == "" { + kc.Logger.Error("service missing valid ClusterIP", "serviceName", service.Name) + continue + } - if service.Annotations != nil { - displayName = service.Annotations["displayName"] - description = service.Annotations["description"] - } + displayName := "" + description := "" - if displayName == "" { - kc.Logger.Warn("service missing displayName annotation", "serviceName", service.Name) - } + if service.Annotations != nil { + displayName = service.Annotations["displayName"] + description = service.Annotations["description"] + } - if description == "" { - kc.Logger.Warn("service missing description annotation", "serviceName", service.Name) - } + if displayName == "" { + kc.Logger.Warn("service missing displayName annotation", "serviceName", service.Name) + } - serviceDetails := ServiceDetails{ - Name: service.Name, - DisplayName: displayName, - Description: description, - ClusterIP: service.Spec.ClusterIP, - HTTPPort: httpPort, - } + if description == "" { + kc.Logger.Warn("service missing description annotation", "serviceName", service.Name) + } - services = append(services, serviceDetails) + serviceDetails := ServiceDetails{ + Name: service.Name, + DisplayName: displayName, + Description: description, + ClusterIP: service.Spec.ClusterIP, + HTTPPort: httpPort, } + + services = append(services, serviceDetails) + } return services, nil @@ -260,6 +250,8 @@ func (kc *KubernetesClient) GetServiceDetailsByName(serviceName string) (Service } func (kc *KubernetesClient) PerformSAR(user string) (bool, error) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() verbs := []string{"get", "list"} resource := "services" @@ -275,7 +267,7 @@ func (kc *KubernetesClient) PerformSAR(user string) (bool, error) { } // Perform the SAR using the native KubernetesNativeClient client - response, err := kc.KubernetesNativeClient.AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), sar, metav1.CreateOptions{}) + response, err := kc.KubernetesNativeClient.AuthorizationV1().SubjectAccessReviews().Create(ctx, sar, metav1.CreateOptions{}) if err != nil { return false, fmt.Errorf("failed to create SubjectAccessReview for verb %q on resource %q: %w", verb, resource, err) } @@ -291,7 +283,7 @@ func (kc *KubernetesClient) PerformSAR(user string) (bool, error) { func (kc *KubernetesClient) IsClusterAdmin(user string) (bool, error) { //using a context here, because checking ClusterRoleBindings could be expensive in large clusters - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() clusterRoleBindings := &rbacv1.ClusterRoleBindingList{} diff --git a/clients/ui/bff/internal/mocks/k8s_mock.go b/clients/ui/bff/internal/mocks/k8s_mock.go index 7d2e86e8..9fcc8a56 100644 --- a/clients/ui/bff/internal/mocks/k8s_mock.go +++ b/clients/ui/bff/internal/mocks/k8s_mock.go @@ -117,6 +117,7 @@ func getProjectRoot() (string, error) { } func setupMock(mockK8sClient client.Client, ctx context.Context) error { + err := createNamespace(mockK8sClient, ctx, "kubeflow") if err != nil { return err @@ -127,15 +128,19 @@ func setupMock(mockK8sClient client.Client, ctx context.Context) error { return err } - err = createService(mockK8sClient, ctx, "model-registry", "kubeflow", "Model Registry", "Model Registry Description", "10.0.0.10") + err = createService(mockK8sClient, ctx, "model-registry", "kubeflow", "Model Registry", "Model Registry Description", "10.0.0.10", "model-registry") + if err != nil { + return err + } + err = createService(mockK8sClient, ctx, "model-registry-dora", "dora-namespace", "Model Registry Dora", "Model Registry Dora description", "10.0.0.11", "model-registry") if err != nil { return err } - err = createService(mockK8sClient, ctx, "model-registry-dora", "dora-namespace", "Model Registry Dora", "Model Registry Dora description", "10.0.0.11") + err = createService(mockK8sClient, ctx, "model-registry-bella", "kubeflow", "Model Registry Bella", "Model Registry Bella description", "10.0.0.12", "model-registry") if err != nil { return err } - err = createService(mockK8sClient, ctx, "model-registry-bella", "kubeflow", "Model Registry Bella", "Model Registry Bella description", "10.0.0.12") + err = createService(mockK8sClient, ctx, "non-model-registry", "kubeflow", "Not a Model Registry", "Not a Model Registry Bella description", "10.0.0.13", "") if err != nil { return err } @@ -183,7 +188,7 @@ func (m *KubernetesClientMock) BearerToken() (string, error) { return "FAKE BEARER TOKEN", nil } -func createService(k8sClient client.Client, ctx context.Context, name string, namespace string, displayName string, description string, clusterIP string) error { +func createService(k8sClient client.Client, ctx context.Context, name string, namespace string, displayName string, description string, clusterIP string, componentLabel string) error { annotations := map[string]string{} @@ -195,15 +200,21 @@ func createService(k8sClient client.Client, ctx context.Context, name string, na annotations["description"] = description } + labels := map[string]string{} + if componentLabel != "" { + labels["component"] = componentLabel + } + service := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, Annotations: annotations, + Labels: labels, }, Spec: corev1.ServiceSpec{ Selector: map[string]string{ - "component": k8s.ComponentName, + "component": k8s.ComponentLabelValue, }, Type: corev1.ServiceTypeClusterIP, ClusterIP: clusterIP, From ba333d7dfc800e2fce1afeab5300bdc1a381c39a Mon Sep 17 00:00:00 2001 From: Lucas Fernandez Date: Fri, 13 Dec 2024 18:46:06 +0100 Subject: [PATCH 08/16] Add support for env variables in the frontend (#642) Signed-off-by: lucferbux --- clients/ui/frontend/.env | 9 + .../ui/frontend/{.eslintrc => .eslintrc.cjs} | 4 +- clients/ui/frontend/.gitignore | 2 +- clients/ui/frontend/config/dotenv.js | 177 +++ clients/ui/frontend/config/webpack.common.js | 189 ++- clients/ui/frontend/config/webpack.dev.js | 134 ++- clients/ui/frontend/config/webpack.prod.js | 87 +- clients/ui/frontend/package-lock.json | 1025 +++++++++++------ clients/ui/frontend/package.json | 33 +- .../__tests__/unit/testUtils/hooks.spec.ts | 6 +- .../ModelVersionDetails.tsx | 2 +- .../RegistrationCommonFormSections.tsx | 2 +- .../frontend/src/images/logo-dark-theme.svg | 43 + .../images/{logo.svg => logo-light-theme.svg} | 0 .../src/shared/components/design/utils.ts | 42 + clients/ui/frontend/tsconfig.json | 18 +- 16 files changed, 1256 insertions(+), 517 deletions(-) create mode 100644 clients/ui/frontend/.env rename clients/ui/frontend/{.eslintrc => .eslintrc.cjs} (99%) create mode 100644 clients/ui/frontend/config/dotenv.js create mode 100644 clients/ui/frontend/src/images/logo-dark-theme.svg rename clients/ui/frontend/src/images/{logo.svg => logo-light-theme.svg} (100%) diff --git a/clients/ui/frontend/.env b/clients/ui/frontend/.env new file mode 100644 index 00000000..39fbc83c --- /dev/null +++ b/clients/ui/frontend/.env @@ -0,0 +1,9 @@ +IS_PROJECT_ROOT_DIR=false +PORT=${FRONTEND_PORT} + +########## Change the following three variables to customize the Dashboard ########## +LOGO=logo-light-theme.svg +LOGO_DARK=logo-dark-theme.svg +FAVICON=favicon.ico +PRODUCT_NAME=Model Registry + diff --git a/clients/ui/frontend/.eslintrc b/clients/ui/frontend/.eslintrc.cjs similarity index 99% rename from clients/ui/frontend/.eslintrc rename to clients/ui/frontend/.eslintrc.cjs index 0ef2cf88..e366d0a9 100644 --- a/clients/ui/frontend/.eslintrc +++ b/clients/ui/frontend/.eslintrc.cjs @@ -1,4 +1,4 @@ -{ +module.exports = { "parser": "@typescript-eslint/parser", "env": { "browser": true, @@ -11,7 +11,7 @@ "js": true, "useJSXTextNode": true, "project": "./tsconfig.json", - "tsconfigRootDir": "." + "tsconfigRootDir": __dirname }, // includes the typescript specific rules found here: https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules "plugins": [ diff --git a/clients/ui/frontend/.gitignore b/clients/ui/frontend/.gitignore index 4731abfe..f53c5d88 100644 --- a/clients/ui/frontend/.gitignore +++ b/clients/ui/frontend/.gitignore @@ -5,4 +5,4 @@ yarn.lock stats.json coverage .idea -.env +public-cypress diff --git a/clients/ui/frontend/config/dotenv.js b/clients/ui/frontend/config/dotenv.js new file mode 100644 index 00000000..c8a64d33 --- /dev/null +++ b/clients/ui/frontend/config/dotenv.js @@ -0,0 +1,177 @@ +const fs = require('fs'); +const path = require('path'); +const dotenv = require('dotenv'); +const dotenvExpand = require('dotenv-expand'); +const Dotenv = require('dotenv-webpack'); + +/** + * Determine if the project is standalone or nested. + * + * @param {string} directory + * @returns {boolean} + */ +const getProjectIsRootDir = (directory) => { + const dotenvLocalFile = path.resolve(directory, '.env.local'); + const dotenvFile = path.resolve(directory, '.env'); + let localIsRoot; + let isRoot; + + if (fs.existsSync(dotenvLocalFile)) { + const { IS_PROJECT_ROOT_DIR: DOTENV_LOCAL_ROOT } = dotenv.parse( + fs.readFileSync(dotenvLocalFile), + ); + localIsRoot = DOTENV_LOCAL_ROOT; + } + + if (fs.existsSync(dotenvFile)) { + const { IS_PROJECT_ROOT_DIR: DOTENV_ROOT } = dotenv.parse(fs.readFileSync(dotenvFile)); + isRoot = DOTENV_ROOT; + } + + return localIsRoot !== undefined ? localIsRoot !== 'false' : isRoot !== 'false'; +}; + +/** + * Return tsconfig compilerOptions. + * + * @param {string} directory + * @returns {object} + */ +const getTsCompilerOptions = (directory) => { + const tsconfigFile = path.resolve(directory, './tsconfig.json'); + let tsCompilerOptions = {}; + + if (fs.existsSync(tsconfigFile)) { + const { compilerOptions = { outDir: './dist', baseUrl: './src' } } = require(tsconfigFile); + tsCompilerOptions = compilerOptions; + } + + return tsCompilerOptions; +}; + +/** + * Setup a webpack dotenv plugin config. + * + * @param {string} path + * @returns {*} + */ +const setupWebpackDotenvFile = (path) => { + const settings = { + systemvars: true, + silent: true, + }; + + if (path) { + settings.path = path; + } + + return new Dotenv(settings); +}; + +/** + * Setup multiple webpack dotenv file parameters. + * + * @param {string} directory + * @param {string} env + * @param {boolean} isRoot + * @returns {Array} + */ +const setupWebpackDotenvFilesForEnv = ({ directory, env, isRoot = true }) => { + const dotenvWebpackSettings = []; + + if (env) { + dotenvWebpackSettings.push( + setupWebpackDotenvFile(path.resolve(directory, `.env.${env}.local`)), + ); + dotenvWebpackSettings.push(setupWebpackDotenvFile(path.resolve(directory, `.env.${env}`))); + } + + dotenvWebpackSettings.push(setupWebpackDotenvFile(path.resolve(directory, '.env.local'))); + dotenvWebpackSettings.push(setupWebpackDotenvFile(path.resolve(directory, '.env'))); + + if (!isRoot) { + if (env) { + dotenvWebpackSettings.push( + setupWebpackDotenvFile(path.resolve(directory, '..', `.env.${env}.local`)), + ); + dotenvWebpackSettings.push( + setupWebpackDotenvFile(path.resolve(directory, '..', `.env.${env}`)), + ); + } + + dotenvWebpackSettings.push(setupWebpackDotenvFile(path.resolve(directory, '..', '.env.local'))); + dotenvWebpackSettings.push(setupWebpackDotenvFile(path.resolve(directory, '..', '.env'))); + } + + return dotenvWebpackSettings; +}; + +/** + * Setup, and access, a dotenv file and the related set of parameters. + * + * @param {string} path + * @returns {*} + */ +const setupDotenvFile = (path) => { + const dotenvInitial = dotenv.config({ path }); + dotenvExpand(dotenvInitial); +}; + +/** + * Setup and access local and specific dotenv file parameters. + * + * @param {string} env + */ +const setupDotenvFilesForEnv = ({ env }) => { + const RELATIVE_DIRNAME = path.resolve(__dirname, '..'); + const IS_ROOT = getProjectIsRootDir(RELATIVE_DIRNAME); + const { baseUrl: TS_BASE_URL, outDir: TS_OUT_DIR } = getTsCompilerOptions(RELATIVE_DIRNAME); + + if (!IS_ROOT) { + if (env) { + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, '..', `.env.${env}.local`)); + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, '..', `.env.${env}`)); + } + + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, '..', '.env.local')); + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, '..', '.env')); + } + + if (env) { + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, `.env.${env}.local`)); + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, `.env.${env}`)); + } + + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, '.env.local')); + setupDotenvFile(path.resolve(RELATIVE_DIRNAME, '.env')); + + const IMAGES_DIRNAME = process.env.IMAGES_DIRNAME || 'images'; + const PUBLIC_PATH = process.env.PUBLIC_PATH || '/'; + const SRC_DIR = path.resolve(RELATIVE_DIRNAME, process.env.SRC_DIR || TS_BASE_URL || 'src'); + const COMMON_DIR = path.resolve(RELATIVE_DIRNAME, process.env.COMMON_DIR || '../common'); + const DIST_DIR = path.resolve(RELATIVE_DIRNAME, process.env.DIST_DIR || TS_OUT_DIR || 'public'); + const HOST = process.env.HOST || 'localhost'; + const PORT = process.env.PORT || '9000'; + const PROXY_PROTOCOL = process.env.PROXY_PROTOCOL || 'http'; + const PROXY_HOST = process.env.PROXY_HOST || 'localhost'; + const PROXY_PORT = process.env.PROXY_PORT || process.env.PORT || 4000; + const DEV_MODE = process.env.DEV_MODE || undefined; + const OUTPUT_ONLY = process.env._OUTPUT_ONLY === 'true'; + + process.env._RELATIVE_DIRNAME = RELATIVE_DIRNAME; + process.env._UI_IS_PROJECT_ROOT_DIR = IS_ROOT; + process.env._IMAGES_DIRNAME = IMAGES_DIRNAME; + process.env._PUBLIC_PATH = PUBLIC_PATH; + process.env._SRC_DIR = SRC_DIR; + process.env._COMMON_DIR = COMMON_DIR; + process.env._DIST_DIR = DIST_DIR; + process.env._HOST = HOST; + process.env._PORT = PORT; + process.env._PROXY_PROTOCOL = PROXY_PROTOCOL; + process.env._PROXY_HOST = PROXY_HOST; + process.env._PROXY_PORT = PROXY_PORT; + process.env._OUTPUT_ONLY = OUTPUT_ONLY; + process.env._DEV_MODE = DEV_MODE; +}; + +module.exports = { setupWebpackDotenvFilesForEnv, setupDotenvFilesForEnv }; diff --git a/clients/ui/frontend/config/webpack.common.js b/clients/ui/frontend/config/webpack.common.js index 6da6aa23..8b8a000e 100644 --- a/clients/ui/frontend/config/webpack.common.js +++ b/clients/ui/frontend/config/webpack.common.js @@ -1,40 +1,68 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); -const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); -const Dotenv = require('dotenv-webpack'); -const ASSET_PATH = process.env.ASSET_PATH || '/'; -const IMAGES_DIRNAME = 'images'; -const relativeDir = path.resolve(__dirname, '..'); +const { setupWebpackDotenvFilesForEnv } = require('./dotenv'); + +const RELATIVE_DIRNAME = process.env._RELATIVE_DIRNAME; +const IS_PROJECT_ROOT_DIR = process.env._IS_PROJECT_ROOT_DIR; +const IMAGES_DIRNAME = process.env._IMAGES_DIRNAME; +const PUBLIC_PATH = process.env._PUBLIC_PATH; +const SRC_DIR = process.env._SRC_DIR; +const COMMON_DIR = process.env._COMMON_DIR; +const DIST_DIR = process.env._DIST_DIR; +const OUTPUT_ONLY = process.env._OUTPUT_ONLY; +const FAVICON = process.env.FAVICON; +const PRODUCT_NAME = process.env.PRODUCT_NAME; +const COVERAGE = process.env.COVERAGE; + +if (OUTPUT_ONLY !== 'true') { + console.info( + `\nPrepping files...\n SRC DIR: ${SRC_DIR}\n OUTPUT DIR: ${DIST_DIR}\n PUBLIC PATH: ${PUBLIC_PATH}\n`, + ); + if (COVERAGE === 'true') { + console.info('\nAdding code coverage instrumentation.\n'); + } +} + module.exports = (env) => { return { + entry: { + app: path.join(SRC_DIR, 'index.tsx'), + }, module: { rules: [ { - test: /\.(tsx|ts|jsx)?$/, + test: /\.(tsx|ts|jsx|js)?$/, + exclude: [/node_modules/, /__tests__/, /__mocks__/], + include: [SRC_DIR, COMMON_DIR], use: [ - { - loader: 'ts-loader', - options: { - transpileOnly: true, - experimentalWatchApi: true - } - } - ] + COVERAGE === 'true' && '@jsdevtools/coverage-istanbul-loader', + env === 'development' + ? { loader: 'swc-loader' } + : { + loader: 'ts-loader', + options: { + transpileOnly: true, + }, + }, + ], }, { test: /\.(svg|ttf|eot|woff|woff2)$/, - type: 'asset/resource', // only process modules with this loader // if they live under a 'fonts' or 'pficon' directory include: [ - path.resolve(relativeDir, 'node_modules/patternfly/dist/fonts'), - path.resolve(relativeDir, 'node_modules/@patternfly/react-core/dist/styles/assets/fonts'), - path.resolve(relativeDir, 'node_modules/@patternfly/react-core/dist/styles/assets/pficon'), - path.resolve(relativeDir, 'node_modules/@patternfly/patternfly/assets/fonts'), - path.resolve(relativeDir, 'node_modules/@patternfly/patternfly/assets/pficon') + path.resolve(RELATIVE_DIRNAME, 'node_modules/patternfly/dist/fonts'), + path.resolve( + RELATIVE_DIRNAME, + 'node_modules/@patternfly/react-core/dist/styles/assets/fonts', + ), + path.resolve( + RELATIVE_DIRNAME, + 'node_modules/@patternfly/react-core/dist/styles/assets/pficon', + ), + path.resolve(RELATIVE_DIRNAME, 'node_modules/@patternfly/patternfly/assets/fonts'), + path.resolve(RELATIVE_DIRNAME, 'node_modules/@patternfly/patternfly/assets/pficon'), ], use: { loader: 'file-loader', @@ -89,34 +117,41 @@ module.exports = (env) => { { test: /\.(jpg|jpeg|png|gif)$/i, include: [ - path.resolve(relativeDir, 'src'), - path.resolve(relativeDir, 'node_modules/patternfly'), - path.resolve(relativeDir, 'node_modules/@patternfly/patternfly/assets/images'), - path.resolve(relativeDir, 'node_modules/@patternfly/react-styles/css/assets/images'), - path.resolve(relativeDir, 'node_modules/@patternfly/react-core/dist/styles/assets/images'), + SRC_DIR, + COMMON_DIR, + path.resolve(RELATIVE_DIRNAME, 'node_modules/patternfly'), + path.resolve(RELATIVE_DIRNAME, 'node_modules/@patternfly/patternfly/assets/images'), path.resolve( - relativeDir, - 'node_modules/@patternfly/react-core/node_modules/@patternfly/react-styles/css/assets/images' + RELATIVE_DIRNAME, + 'node_modules/@patternfly/react-styles/css/assets/images', ), path.resolve( - relativeDir, - 'node_modules/@patternfly/react-table/node_modules/@patternfly/react-styles/css/assets/images' + RELATIVE_DIRNAME, + 'node_modules/@patternfly/react-core/dist/styles/assets/images', ), path.resolve( - relativeDir, - 'node_modules/@patternfly/react-inline-edit-extension/node_modules/@patternfly/react-styles/css/assets/images' - ) + RELATIVE_DIRNAME, + 'node_modules/@patternfly/react-core/node_modules/@patternfly/react-styles/css/assets/images', + ), + path.resolve( + RELATIVE_DIRNAME, + 'node_modules/@patternfly/react-table/node_modules/@patternfly/react-styles/css/assets/images', + ), + path.resolve( + RELATIVE_DIRNAME, + 'node_modules/@patternfly/react-inline-edit-extension/node_modules/@patternfly/react-styles/css/assets/images', + ), ], - type: 'asset/inline', use: [ { + loader: 'url-loader', options: { limit: 5000, outputPath: 'images', - name: '[name].[ext]' - } - } - ] + name: '[name].[ext]', + }, + }, + ], }, { test: /\.s[ac]ss$/i, @@ -128,35 +163,75 @@ module.exports = (env) => { // Compiles Sass to CSS 'sass-loader', ], - } - ] + }, + { + test: /\.ya?ml$/, + use: 'js-yaml-loader', + }, + ], }, output: { filename: '[name].bundle.js', - path: path.resolve(relativeDir, 'dist'), - publicPath: ASSET_PATH + path: DIST_DIR, + publicPath: PUBLIC_PATH, }, plugins: [ - new HtmlWebpackPlugin({ - template: path.resolve(relativeDir, 'src', 'index.html') + ...setupWebpackDotenvFilesForEnv({ + directory: RELATIVE_DIRNAME, + isRoot: IS_PROJECT_ROOT_DIR, }), - new Dotenv({ - systemvars: true, - silent: true + new HtmlWebpackPlugin({ + template: path.join(SRC_DIR, 'index.html'), + title: PRODUCT_NAME, + favicon: path.join(SRC_DIR, 'images', FAVICON), }), new CopyPlugin({ - patterns: [{ from: './src/images', to: 'images' }] - }) + patterns: [ + { + from: path.join(SRC_DIR, 'locales'), + to: path.join(DIST_DIR, 'locales'), + noErrorOnMissing: true, + }, + { + from: path.join(SRC_DIR, 'favicons'), + to: path.join(DIST_DIR, 'favicons'), + noErrorOnMissing: true, + }, + { + from: path.join(SRC_DIR, 'images'), + to: path.join(DIST_DIR, 'images'), + noErrorOnMissing: true, + }, + { + from: path.join(SRC_DIR, 'favicon.ico'), + to: path.join(DIST_DIR), + noErrorOnMissing: true, + }, + { + from: path.join(SRC_DIR, 'favicon.png'), + to: path.join(DIST_DIR), + noErrorOnMissing: true, + }, + { + from: path.join(SRC_DIR, 'manifest.json'), + to: path.join(DIST_DIR), + noErrorOnMissing: true, + }, + { + from: path.join(SRC_DIR, 'robots.txt'), + to: path.join(DIST_DIR), + noErrorOnMissing: true, + }, + ], + }), ], resolve: { extensions: ['.js', '.ts', '.tsx', '.jsx'], - plugins: [ - new TsconfigPathsPlugin({ - configFile: path.resolve(relativeDir, './tsconfig.json') - }) - ], + alias: { + '~': path.resolve(SRC_DIR), + }, symlinks: false, - cacheWithContext: false - } + cacheWithContext: false, + }, }; }; diff --git a/clients/ui/frontend/config/webpack.dev.js b/clients/ui/frontend/config/webpack.dev.js index b2198a83..89d98025 100644 --- a/clients/ui/frontend/config/webpack.dev.js +++ b/clients/ui/frontend/config/webpack.dev.js @@ -1,48 +1,100 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - +const { execSync } = require('child_process'); const path = require('path'); const { merge } = require('webpack-merge'); -const common = require('./webpack.common.js'); -const { stylePaths } = require('./stylePaths'); -const HOST = process.env.HOST || 'localhost'; -const PORT = process.env.PORT || '9000'; -const PROXY_HOST = process.env.PROXY_HOST || 'localhost'; -const PROXY_PORT = process.env.PROXY_PORT || '4000'; -const PROXY_PROTOCOL = process.env.PROXY_PROTOCOL || 'http:'; -const relativeDir = path.resolve(__dirname, '..'); +const { setupWebpackDotenvFilesForEnv, setupDotenvFilesForEnv } = require('./dotenv'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); +const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); -module.exports = merge(common('development'), { - mode: 'development', - devtool: 'eval-source-map', - devServer: { - host: HOST, - port: PORT, - historyApiFallback: true, - static: { - directory: path.resolve(relativeDir, 'dist'), - }, - client: { - overlay: true, +const smp = new SpeedMeasurePlugin({ disable: !process.env.MEASURE }); + +setupDotenvFilesForEnv({ env: 'development' }); +const webpackCommon = require('./webpack.common.js'); + +const RELATIVE_DIRNAME = process.env._RELATIVE_DIRNAME; +const IS_PROJECT_ROOT_DIR = process.env._IS_PROJECT_ROOT_DIR; +const SRC_DIR = process.env._SRC_DIR; +const COMMON_DIR = process.env._COMMON_DIR; +const DIST_DIR = process.env._DIST_DIR; +const HOST = process.env._HOST; +const PORT = process.env._PORT; +const PROXY_PROTOCOL = process.env._PROXY_PROTOCOL; +const PROXY_HOST = process.env._PROXY_HOST; +const PROXY_PORT = process.env._PROXY_PORT; + +module.exports = smp.wrap( + merge( + { + plugins: [ + ...setupWebpackDotenvFilesForEnv({ + directory: RELATIVE_DIRNAME, + env: 'development', + isRoot: IS_PROJECT_ROOT_DIR, + }), + ], }, - proxy: [ - { - context: ["/api"], - target: { - host: PROXY_HOST, - protocol: PROXY_PROTOCOL, - port: PROXY_PORT, + webpackCommon('development'), + { + mode: 'development', + devtool: 'eval-source-map', + optimization: { + runtimeChunk: 'single', + removeEmptyChunks: true, + }, + devServer: { + host: HOST, + port: PORT, + compress: true, + historyApiFallback: true, + hot: true, + open: false, + proxy: [ + { + context: ["/api"], + target: { + host: PROXY_HOST, + protocol: PROXY_PROTOCOL, + port: PROXY_PORT, + }, + changeOrigin: true, + }, + ], + devMiddleware: { + stats: 'errors-only', + }, + client: { + overlay: false, + }, + static: { + directory: DIST_DIR, + }, + onListening: (devServer) => { + if (devServer) { + console.log( + `\x1b[32m✓ Dashboard available at: \x1b[4mhttp://localhost:${ + devServer.server.address().port + }\x1b[0m`, + ); + } }, - changeOrigin: true, }, - ], - }, - module: { - rules: [ - { - test: /\.css$/, - include: [...stylePaths], - use: ['style-loader', 'css-loader'], + module: { + rules: [ + { + test: /\.css$/, + include: [ + SRC_DIR, + COMMON_DIR, + path.resolve(RELATIVE_DIRNAME, 'node_modules/@patternfly'), + ], + use: ['style-loader', 'css-loader'], + }, + ], }, - ], - }, -}); + plugins: [ + new ForkTsCheckerWebpackPlugin(), + new ReactRefreshWebpackPlugin({ overlay: false }), + ], + }, + ), +); diff --git a/clients/ui/frontend/config/webpack.prod.js b/clients/ui/frontend/config/webpack.prod.js index 906e2dc4..a14ef40f 100644 --- a/clients/ui/frontend/config/webpack.prod.js +++ b/clients/ui/frontend/config/webpack.prod.js @@ -1,38 +1,61 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - +const path = require('path'); const { merge } = require('webpack-merge'); -const common = require('./webpack.common.js'); -const { stylePaths } = require('./stylePaths'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const TerserJSPlugin = require('terser-webpack-plugin'); +const { setupWebpackDotenvFilesForEnv, setupDotenvFilesForEnv } = require('./dotenv'); + +setupDotenvFilesForEnv({ env: 'production' }); +const webpackCommon = require('./webpack.common.js'); + +const RELATIVE_DIRNAME = process.env._RELATIVE_DIRNAME; +const IS_PROJECT_ROOT_DIR = process.env._IS_PROJECT_ROOT_DIR; +const SRC_DIR = process.env._SRC_DIR; +const COMMON_DIR = process.env._COMMON_DIR; +const DIST_DIR = process.env._DIST_DIR; +const OUTPUT_ONLY = process.env._OUTPUT_ONLY; -module.exports = merge(common('production'), { - mode: 'production', - devtool: 'source-map', - optimization: { - minimizer: [ - new TerserJSPlugin({}), - new CssMinimizerPlugin({ - minimizerOptions: { - preset: ['default', { mergeLonghand: false }] - } - }) - ] +if (OUTPUT_ONLY !== 'true') { + console.info(`Cleaning OUTPUT DIR...\n ${DIST_DIR}\n`); +} + +module.exports = merge( + { + plugins: [ + ...setupWebpackDotenvFilesForEnv({ + directory: RELATIVE_DIRNAME, + env: 'production', + isRoot: IS_PROJECT_ROOT_DIR, + }), + ], + }, + webpackCommon('production'), + { + mode: 'production', + devtool: 'source-map', + optimization: { + minimize: true, + minimizer: [new TerserJSPlugin(), new CssMinimizerPlugin()], + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: '[name].css', + chunkFilename: '[name].bundle.css', + ignoreOrder: true, + }), + ], + module: { + rules: [ + { + test: /\.css$/, + include: [ + SRC_DIR, + COMMON_DIR, + path.resolve(RELATIVE_DIRNAME, 'node_modules/@patternfly'), + ], + use: [MiniCssExtractPlugin.loader, 'css-loader'], + }, + ], + }, }, - plugins: [ - new MiniCssExtractPlugin({ - filename: '[name].css', - chunkFilename: '[name].bundle.css' - }) - ], - module: { - rules: [ - { - test: /\.css$/, - include: [...stylePaths], - use: [MiniCssExtractPlugin.loader, 'css-loader'] - } - ] - } -}); +); diff --git a/clients/ui/frontend/package-lock.json b/clients/ui/frontend/package-lock.json index ee0bf564..503b8b2c 100644 --- a/clients/ui/frontend/package-lock.json +++ b/clients/ui/frontend/package-lock.json @@ -11,13 +11,14 @@ "dependencies": { "@emotion/react": "^11.13.5", "@emotion/styled": "^11.13.5", + "@patternfly/patternfly": "^6.0.0", "@patternfly/react-core": "6.0.0", "@patternfly/react-icons": "6.0.0", "@patternfly/react-styles": "6.0.0", "@patternfly/react-table": "6.0.0", "@patternfly/react-templates": "6.0.0", "classnames": "^2.2.6", - "dompurify": "^3.2.0", + "dompurify": "^2.2.6", "lodash-es": "^4.17.15", "npm-run-all": "^4.1.5", "react": "^18", @@ -34,13 +35,15 @@ "@mui/icons-material": "^6.1.10", "@mui/material": "^6.1.7", "@mui/types": "^7.2.17", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", + "@swc/core": "^1.9.1", "@testing-library/cypress": "^10.0.1", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.2", "@testing-library/react": "^16.0.0", "@testing-library/user-event": "14.5.2", "@types/classnames": "^2.3.1", - "@types/dompurify": "^3.0.5", + "@types/dompurify": "^2.2.6", "@types/jest": "^29.5.13", "@types/lodash-es": "^4.17.8", "@types/react-dom": "^18.3.1", @@ -56,9 +59,12 @@ "cypress-high-resolution": "^1.0.0", "cypress-mochawesome-reporter": "^3.8.2", "cypress-multi-reporters": "^2.0.4", - "dotenv": "^16.4.5", - "dotenv-webpack": "^8.1.0", + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "dotenv-webpack": "^6.0.0", "expect": "^29.7.0", + "file-loader": "^6.1.1", + "fork-ts-checker-webpack-plugin": "^9.0.2", "html-webpack-plugin": "^5.6.3", "imagemin": "^9.0.0", "jest": "^29.7.0", @@ -69,13 +75,16 @@ "prettier": "^3.3.3", "prop-types": "^15.8.1", "raw-loader": "^4.0.2", + "react-refresh": "^0.14.2", "react-router-dom": "^7.0.2", "regenerator-runtime": "^0.14.1", - "rimraf": "^6.0.1", - "sass-loader": "^16.0.1", + "sass": "^1.56.2", + "sass-loader": "^13.2.0", "serve": "^14.2.4", - "style-loader": "^4.0.0", - "svg-url-loader": "^8.0.0", + "speed-measure-webpack-plugin": "^1.5.0", + "style-loader": "^2.0.0", + "svg-url-loader": "^6.0.0", + "swc-loader": "^0.2.6", "terser-webpack-plugin": "^5.3.10", "ts-jest": "^29.2.5", "ts-loader": "^9.5.1", @@ -83,7 +92,7 @@ "tslib": "^2.7.0", "typescript": "^5.7.2", "url-loader": "^4.1.1", - "webpack": "^5.95.0", + "webpack": "^5.96.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.1.0", @@ -2446,102 +2455,6 @@ "license": "BSD-3-Clause", "optional": true }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -3453,6 +3366,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -3492,6 +3406,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3512,6 +3427,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3532,6 +3448,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3552,6 +3469,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3572,6 +3490,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3592,6 +3511,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3612,6 +3532,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3632,6 +3553,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3652,6 +3574,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3672,6 +3595,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3692,6 +3616,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3712,6 +3637,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3732,6 +3658,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3745,6 +3672,12 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@patternfly/patternfly": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-6.0.0.tgz", + "integrity": "sha512-Mn92Tt/4okSj1COGCJrgUgh390OOaFCWf0tL0WmigDNUecSHNn1D6Vhpd1hxHQBXvre9eWorzxV2b9yhSEl79Q==", + "license": "MIT" + }, "node_modules/@patternfly/react-core": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-6.0.0.tgz", @@ -3833,6 +3766,65 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.15.tgz", + "integrity": "sha512-LFWllMA55pzB9D34w/wXUCf8+c+IYKuJDgxiZ3qMhl64KRMBHYM1I3VdGaD2BV5FNPV2/S2596bppxHbv2ZydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-html": "^0.0.9", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^4.2.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x || 5.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.28", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", @@ -3918,6 +3910,232 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@swc/core": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.1.tgz", + "integrity": "sha512-rQ4dS6GAdmtzKiCRt3LFVxl37FaY1cgL9kSUTnhQ2xc3fmHOd7jdJK/V4pSZMG1ruGTd0bsi34O2R0Olg9Zo/w==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.17" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.10.1", + "@swc/core-darwin-x64": "1.10.1", + "@swc/core-linux-arm-gnueabihf": "1.10.1", + "@swc/core-linux-arm64-gnu": "1.10.1", + "@swc/core-linux-arm64-musl": "1.10.1", + "@swc/core-linux-x64-gnu": "1.10.1", + "@swc/core-linux-x64-musl": "1.10.1", + "@swc/core-win32-arm64-msvc": "1.10.1", + "@swc/core-win32-ia32-msvc": "1.10.1", + "@swc/core-win32-x64-msvc": "1.10.1" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.1.tgz", + "integrity": "sha512-NyELPp8EsVZtxH/mEqvzSyWpfPJ1lugpTQcSlMduZLj1EASLO4sC8wt8hmL1aizRlsbjCX+r0PyL+l0xQ64/6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.1.tgz", + "integrity": "sha512-L4BNt1fdQ5ZZhAk5qoDfUnXRabDOXKnXBxMDJ+PWLSxOGBbWE6aJTnu4zbGjJvtot0KM46m2LPAPY8ttknqaZA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.1.tgz", + "integrity": "sha512-Y1u9OqCHgvVp2tYQAJ7hcU9qO5brDMIrA5R31rwWQIAKDkJKtv3IlTHF0hrbWk1wPR0ZdngkQSJZple7G+Grvw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.1.tgz", + "integrity": "sha512-tNQHO/UKdtnqjc7o04iRXng1wTUXPgVd8Y6LI4qIbHVoVPwksZydISjMcilKNLKIwOoUQAkxyJ16SlOAeADzhQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.1.tgz", + "integrity": "sha512-x0L2Pd9weQ6n8dI1z1Isq00VHFvpBClwQJvrt3NHzmR+1wCT/gcYl1tp9P5xHh3ldM8Cn4UjWCw+7PaUgg8FcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.1.tgz", + "integrity": "sha512-yyYEwQcObV3AUsC79rSzN9z6kiWxKAVJ6Ntwq2N9YoZqSPYph+4/Am5fM1xEQYf/kb99csj0FgOelomJSobxQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.1.tgz", + "integrity": "sha512-tcaS43Ydd7Fk7sW5ROpaf2Kq1zR+sI5K0RM+0qYLYYurvsJruj3GhBCaiN3gkzd8m/8wkqNqtVklWaQYSDsyqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.1.tgz", + "integrity": "sha512-D3Qo1voA7AkbOzQ2UGuKNHfYGKL6eejN8VWOoQYtGHHQi1p5KK/Q7V1ku55oxXBsj79Ny5FRMqiRJpVGad7bjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.1.tgz", + "integrity": "sha512-WalYdFoU3454Og+sDKHM1MrjvxUGwA2oralknXkXL8S0I/8RkWZOB++p3pLaGbTvOO++T+6znFbQdR8KRaa7DA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.1.tgz", + "integrity": "sha512-JWobfQDbTnoqaIwPKQ3DVSywihVXlQMbDuwik/dDWlj33A8oEHcjPOGs4OqcA3RHv24i+lfCQpM3Mn4FAMfacA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz", + "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@testing-library/cypress": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-10.0.2.tgz", @@ -4179,9 +4397,9 @@ "license": "MIT" }, "node_modules/@types/dompurify": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", - "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz", + "integrity": "sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg==", "dev": true, "license": "MIT", "dependencies": { @@ -5287,6 +5505,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-html": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", + "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -7159,6 +7390,18 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-js-pure": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.39.0.tgz", + "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -8047,6 +8290,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, "license": "Apache-2.0", "optional": true, "bin": { @@ -8229,9 +8473,10 @@ } }, "node_modules/dompurify": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.0.tgz", - "integrity": "sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz", + "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", + "license": "(MPL-2.0 OR Apache-2.0)" }, "node_modules/domutils": { "version": "2.8.0", @@ -8289,16 +8534,13 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" + "node": ">=10" } }, "node_modules/dotenv-defaults": { @@ -8311,30 +8553,24 @@ "dotenv": "^8.2.0" } }, - "node_modules/dotenv-defaults/node_modules/dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=10" - } + "license": "BSD-2-Clause" }, "node_modules/dotenv-webpack": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz", - "integrity": "sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-6.0.4.tgz", + "integrity": "sha512-WiTPNLanDNJ1O8AvgkBpsbarw78a4PMYG2EfJcQoxTHFWy+ji213HR+3f4PhWB1RBumiD9cbiuC3SNxJXbBp9g==", "dev": true, "license": "MIT", "dependencies": { - "dotenv-defaults": "^2.0.2" - }, - "engines": { - "node": ">=10" + "dotenv-defaults": "^2.0.1" }, "peerDependencies": { - "webpack": "^4 || ^5" + "webpack": "^1 || ^2 || ^3 || ^4 || ^5" } }, "node_modules/duplexer": { @@ -8518,6 +8754,16 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, "node_modules/es-abstract": { "version": "1.23.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", @@ -10126,6 +10372,146 @@ "node": "*" } }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/form-data": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", @@ -10198,6 +10584,13 @@ "node": ">=10" } }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true, + "license": "Unlicense" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -11175,6 +11568,7 @@ "version": "4.3.7", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "dev": true, "license": "MIT" }, "node_modules/import-fresh": { @@ -12188,22 +12582,6 @@ "node": ">= 0.4" } }, - "node_modules/jackspeak": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", - "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/jake": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", @@ -14133,16 +14511,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/mocha": { "version": "10.8.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", @@ -14597,10 +14965,18 @@ "tslib": "^2.0.3" } }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true, + "license": "MIT" + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, "license": "MIT", "optional": true }, @@ -15548,13 +15924,6 @@ "node": ">=8" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -15673,33 +16042,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", - "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/path-to-regexp": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", @@ -16912,6 +17254,16 @@ "dev": true, "license": "MIT" }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-router": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.0.2.tgz", @@ -17412,96 +17764,6 @@ "dev": true, "license": "MIT" }, - "node_modules/rimraf": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", - "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^11.0.0", - "package-json-from-dist": "^1.0.0" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", - "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -17616,6 +17878,7 @@ "version": "1.80.6", "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.6.tgz", "integrity": "sha512-ccZgdHNiBF1NHBsWvacvT5rju3y1d/Eu+8Ex6c21nHp2lZGLBEtuwc415QfiI1PJa1TpCo3iXwwSRjRpn2Ckjg==", + "dev": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.0", @@ -17633,30 +17896,30 @@ } }, "node_modules/sass-loader": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.3.tgz", - "integrity": "sha512-gosNorT1RCkuCMyihv6FBRR7BMV06oKRAs+l4UMp1mlcVg9rWN6KMmUj3igjQwmYys4mDP3etEYJgiHRbgHCHA==", + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz", + "integrity": "sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==", "dev": true, "license": "MIT", "dependencies": { "neo-async": "^2.6.2" }, "engines": { - "node": ">= 18.12.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "@rspack/core": "0.x || 1.x", + "fibers": ">= 3.1.0", "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "peerDependenciesMeta": { - "@rspack/core": { + "fibers": { "optional": true }, "node-sass": { @@ -17667,9 +17930,6 @@ }, "sass-embedded": { "optional": true - }, - "webpack": { - "optional": true } } }, @@ -17677,6 +17937,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -17692,6 +17953,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.16.0" @@ -18330,6 +18592,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -18471,6 +18734,22 @@ "wbuf": "^1.7.3" } }, + "node_modules/speed-measure-webpack-plugin": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.5.0.tgz", + "integrity": "sha512-Re0wX5CtM6gW7bZA64ONOfEPEhwbiSF/vz6e2GvadjuaPrQcHTQdRGsD8+BE7iUOysXH8tIenkPCQBEcspXsNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "webpack": "^1 || ^2 || ^3 || ^4 || ^5" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -18527,6 +18806,13 @@ "node": ">=8" } }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -18576,29 +18862,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -18739,20 +19002,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -18818,20 +19067,43 @@ } }, "node_modules/style-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", - "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz", + "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", "dev": true, "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, "engines": { - "node": ">= 18.12.0" + "node": ">= 10.13.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.27.0" + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/style-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/stylehacks": { @@ -18900,19 +19172,57 @@ } }, "node_modules/svg-url-loader": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/svg-url-loader/-/svg-url-loader-8.0.0.tgz", - "integrity": "sha512-5doSXvl18hY1fGsRLdhWAU5jgzgxJ06/gc/26cpuDnN0xOz1HmmfhkpL29SSrdIvhtxQ1UwGzmk7wTT/l48mKw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/svg-url-loader/-/svg-url-loader-6.0.0.tgz", + "integrity": "sha512-Qr5SCKxyxKcRnvnVrO3iQj9EX/v40UiGEMshgegzV7vpo3yc+HexELOdtWcA3MKjL8IyZZ1zOdcILmDEa/8JJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-loader": "~6.0.0", + "loader-utils": "~2.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/svg-url-loader/node_modules/file-loader": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz", + "integrity": "sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==", "dev": true, "license": "MIT", "dependencies": { - "file-loader": "~6.2.0" + "loader-utils": "^2.0.0", + "schema-utils": "^2.6.5" }, "engines": { - "node": ">=14" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/svg-url-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/svgo": { @@ -19014,6 +19324,20 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/swc-loader": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", + "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/counter": "^0.1.3" + }, + "peerDependencies": { + "@swc/core": "^1.2.147", + "webpack": ">=2" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -20838,25 +21162,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/clients/ui/frontend/package.json b/clients/ui/frontend/package.json index 510d3970..7e86bbd5 100644 --- a/clients/ui/frontend/package.json +++ b/clients/ui/frontend/package.json @@ -14,8 +14,8 @@ "build:analyze": "run-s build build:bundle-profile build:bundle-analyze", "build:bundle-profile": "webpack --config ./config/webpack.prod.js --profile --json > ./bundle.stats.json", "build:bundle-analyze": "webpack-bundle-analyzer ./bundle.stats.json", - "build:clean": "rimraf ./public", "build:prod": "webpack --config ./config/webpack.prod.js", + "build:clean": "rm -rf ./dist", "start:dev": "webpack serve --hot --color --config ./config/webpack.dev.js", "test": "run-s test:lint test:unit test:cypress-ci", "test:cypress-ci": "npx concurrently -P -k -s first \"npm run cypress:server:build && npm run cypress:server\" \"npx wait-on tcp:127.0.0.1:9001 && npm run cypress:run:mock -- {@}\" -- ", @@ -27,10 +27,12 @@ "cypress:open:mock": "CY_MOCK=1 npm run cypress:open -- ", "cypress:run": "cypress run -b chrome --project src/__tests__/cypress", "cypress:run:mock": "CY_MOCK=1 npm run cypress:run -- ", - "cypress:server:build": "POLL_INTERVAL=9999999 FAST_POLL_INTERVAL=9999999 npm run build", - "cypress:server": "serve ./dist -p 9001 -s -L" + "cypress:server:build": "DIST_DIR=./public-cypress POLL_INTERVAL=9999999 FAST_POLL_INTERVAL=9999999 npm run build", + "cypress:server": "serve ./public-cypress -p 9001 -s -L" }, "devDependencies": { + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", + "@swc/core": "^1.9.1", "@babel/preset-env": "^7.21.5", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.5", @@ -44,7 +46,7 @@ "@testing-library/react": "^16.0.0", "@testing-library/user-event": "14.5.2", "@types/classnames": "^2.3.1", - "@types/dompurify": "^3.0.5", + "@types/dompurify": "^2.2.6", "@types/jest": "^29.5.13", "@types/lodash-es": "^4.17.8", "@types/react-dom": "^18.3.1", @@ -60,9 +62,12 @@ "cypress-high-resolution": "^1.0.0", "cypress-mochawesome-reporter": "^3.8.2", "cypress-multi-reporters": "^2.0.4", - "dotenv": "^16.4.5", - "dotenv-webpack": "^8.1.0", + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "dotenv-webpack": "^6.0.0", "expect": "^29.7.0", + "file-loader": "^6.1.1", + "fork-ts-checker-webpack-plugin": "^9.0.2", "html-webpack-plugin": "^5.6.3", "imagemin": "^9.0.0", "jest": "^29.7.0", @@ -73,13 +78,16 @@ "prettier": "^3.3.3", "prop-types": "^15.8.1", "raw-loader": "^4.0.2", + "react-refresh": "^0.14.2", "react-router-dom": "^7.0.2", "regenerator-runtime": "^0.14.1", - "rimraf": "^6.0.1", - "sass-loader": "^16.0.1", + "sass": "^1.56.2", + "sass-loader": "^13.2.0", "serve": "^14.2.4", - "style-loader": "^4.0.0", - "svg-url-loader": "^8.0.0", + "speed-measure-webpack-plugin": "^1.5.0", + "style-loader": "^2.0.0", + "svg-url-loader": "^6.0.0", + "swc-loader": "^0.2.6", "terser-webpack-plugin": "^5.3.10", "ts-jest": "^29.2.5", "ts-loader": "^9.5.1", @@ -87,7 +95,7 @@ "tslib": "^2.7.0", "typescript": "^5.7.2", "url-loader": "^4.1.1", - "webpack": "^5.95.0", + "webpack": "^5.96.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.1.0", @@ -96,6 +104,7 @@ "dependencies": { "@emotion/react": "^11.13.5", "@emotion/styled": "^11.13.5", + "@patternfly/patternfly": "^6.0.0", "@patternfly/react-core": "6.0.0", "@patternfly/react-icons": "6.0.0", "@patternfly/react-styles": "6.0.0", @@ -107,7 +116,7 @@ "react-dom": "^18", "react-router": "^7.0.2", "sass": "^1.78.0", - "dompurify": "^3.2.0", + "dompurify": "^2.2.6", "showdown": "^2.1.0", "classnames": "^2.2.6" }, diff --git a/clients/ui/frontend/src/__tests__/unit/testUtils/hooks.spec.ts b/clients/ui/frontend/src/__tests__/unit/testUtils/hooks.spec.ts index f570f974..d2509314 100644 --- a/clients/ui/frontend/src/__tests__/unit/testUtils/hooks.spec.ts +++ b/clients/ui/frontend/src/__tests__/unit/testUtils/hooks.spec.ts @@ -70,11 +70,11 @@ describe('hook test utils', () => { expect(renderResult).hookToBe('Hello world!'); expect(renderResult).hookToStrictEqual('Hello world!'); - renderResult.rerender({ who: 'world', showCount: true }); + renderResult.rerender({ who: 'world' }); expect(renderResult).hookToHaveUpdateCount(3); - expect(renderResult).hookToBe('Hello world! x3'); - expect(renderResult).hookToStrictEqual('Hello world! x3'); + expect(renderResult).hookToBe('Hello world!'); + expect(renderResult).hookToStrictEqual('Hello world!'); }); it('should use waitForNextUpdate for async update testing', async () => { diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx index 8bbcd176..c59fecab 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx @@ -90,7 +90,7 @@ const ModelVersionsDetails: React.FC = ({ tab, ...page /> - + ) diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/RegistrationCommonFormSections.tsx b/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/RegistrationCommonFormSections.tsx index eb67141c..8a106325 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/RegistrationCommonFormSections.tsx +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/RegistrationCommonFormSections.tsx @@ -217,7 +217,7 @@ const RegistrationCommonFormSections: React.FC diff --git a/clients/ui/frontend/src/images/logo-dark-theme.svg b/clients/ui/frontend/src/images/logo-dark-theme.svg new file mode 100644 index 00000000..fb06122e --- /dev/null +++ b/clients/ui/frontend/src/images/logo-dark-theme.svg @@ -0,0 +1,43 @@ + + + + Kubeflow Logo + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clients/ui/frontend/src/images/logo.svg b/clients/ui/frontend/src/images/logo-light-theme.svg similarity index 100% rename from clients/ui/frontend/src/images/logo.svg rename to clients/ui/frontend/src/images/logo-light-theme.svg diff --git a/clients/ui/frontend/src/shared/components/design/utils.ts b/clients/ui/frontend/src/shared/components/design/utils.ts index df39b392..36d39055 100644 --- a/clients/ui/frontend/src/shared/components/design/utils.ts +++ b/clients/ui/frontend/src/shared/components/design/utils.ts @@ -7,6 +7,14 @@ import './vars.scss'; /* eslint-disable @typescript-eslint/no-unnecessary-condition */ // These conditions are required for future object types that may be added later. +export enum SectionType { + setup = 'set-up', + organize = 'organize', + training = 'training', + serving = 'serving', + general = 'general', +} + export enum ProjectObjectType { registeredModels = 'registered-models', } @@ -44,3 +52,37 @@ export const typedEmptyImage = (objectType: ProjectObjectType, option?: string): return ''; } }; + +export const sectionTypeBackgroundColor = (sectionType: SectionType): string => { + switch (sectionType) { + case SectionType.setup: + return 'var(--ai-set-up--BackgroundColor)'; + case SectionType.organize: + return 'var(--ai-organize--BackgroundColor)'; + case SectionType.training: + return 'var(--ai-training--BackgroundColor)'; + case SectionType.serving: + return 'var(--ai-serving--BackgroundColor)'; + case SectionType.general: + return 'var(--ai-general--BackgroundColor)'; + default: + return ''; + } +}; + +export const sectionTypeBorderColor = (sectionType: SectionType): string => { + switch (sectionType) { + case SectionType.setup: + return 'var(--ai-set-up--BorderColor)'; + case SectionType.organize: + return 'var(--ai-organize--BorderColor)'; + case SectionType.training: + return 'var(--ai-training--BorderColor)'; + case SectionType.serving: + return 'var(--ai-serving--BorderColor)'; + case SectionType.general: + return 'var(--ai-general--BorderColor)'; + default: + return ''; + } +}; diff --git a/clients/ui/frontend/tsconfig.json b/clients/ui/frontend/tsconfig.json index 674889be..1d11ee22 100644 --- a/clients/ui/frontend/tsconfig.json +++ b/clients/ui/frontend/tsconfig.json @@ -1,14 +1,13 @@ { "compilerOptions": { - "baseUrl": "./src", "rootDir": ".", "outDir": "dist", "module": "esnext", "target": "es5", "lib": [ - "ESNext.Array", "es6", - "dom" + "dom", + "ES2023.Array" ], "sourceMap": true, "jsx": "react", @@ -22,21 +21,26 @@ "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, + "baseUrl": "./src", "paths": { - "~/*": ["./*"] + "~/*": [ + "./*" + ] }, "importHelpers": true, - "skipLibCheck": true + "skipLibCheck": true, + "noErrorTruncation": true }, "include": [ "**/*.ts", "**/*.tsx", "**/*.jsx", - "**/*.js", + "**/*.js" ], "exclude": [ "node_modules", "dist", + "public-cypress", "src/__tests__/cypress" ] -} +} \ No newline at end of file From f6feaebc5a99f70eb403fa0184b140b933b516d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:41:08 +0000 Subject: [PATCH 09/16] build(deps): bump dompurify and @types/dompurify in /clients/ui/frontend (#649) Bumps [dompurify](https://github.com/cure53/DOMPurify) and [@types/dompurify](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/dompurify). These dependencies needed to be updated together. Updates `dompurify` from 2.5.8 to 3.2.3 - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/2.5.8...3.2.3) Updates `@types/dompurify` from 2.4.0 to 3.2.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/dompurify) --- updated-dependencies: - dependency-name: dompurify dependency-type: direct:production update-type: version-update:semver-major - dependency-name: "@types/dompurify" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- clients/ui/frontend/package-lock.json | 27 ++++++++++++++------------- clients/ui/frontend/package.json | 4 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/clients/ui/frontend/package-lock.json b/clients/ui/frontend/package-lock.json index 503b8b2c..71842ba3 100644 --- a/clients/ui/frontend/package-lock.json +++ b/clients/ui/frontend/package-lock.json @@ -18,7 +18,7 @@ "@patternfly/react-table": "6.0.0", "@patternfly/react-templates": "6.0.0", "classnames": "^2.2.6", - "dompurify": "^2.2.6", + "dompurify": "^3.2.3", "lodash-es": "^4.17.15", "npm-run-all": "^4.1.5", "react": "^18", @@ -43,7 +43,7 @@ "@testing-library/react": "^16.0.0", "@testing-library/user-event": "14.5.2", "@types/classnames": "^2.3.1", - "@types/dompurify": "^2.2.6", + "@types/dompurify": "^3.2.0", "@types/jest": "^29.5.13", "@types/lodash-es": "^4.17.8", "@types/react-dom": "^18.3.1", @@ -4397,13 +4397,13 @@ "license": "MIT" }, "node_modules/@types/dompurify": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.4.0.tgz", - "integrity": "sha512-IDBwO5IZhrKvHFUl+clZxgf3hn2b/lU6H1KaBShPkQyGJUQ0xwebezIPSuiyGwfz1UzJWQl4M7BDxtHtCCPlTg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.2.0.tgz", + "integrity": "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==", + "deprecated": "This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.", "dev": true, - "license": "MIT", "dependencies": { - "@types/trusted-types": "*" + "dompurify": "*" } }, "node_modules/@types/eslint": { @@ -4821,8 +4821,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "dev": true, - "license": "MIT" + "optional": true }, "node_modules/@types/ws": { "version": "8.5.13", @@ -8473,10 +8472,12 @@ } }, "node_modules/dompurify": { - "version": "2.5.8", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz", - "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", - "license": "(MPL-2.0 OR Apache-2.0)" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz", + "integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/domutils": { "version": "2.8.0", diff --git a/clients/ui/frontend/package.json b/clients/ui/frontend/package.json index 7e86bbd5..075d02cf 100644 --- a/clients/ui/frontend/package.json +++ b/clients/ui/frontend/package.json @@ -46,7 +46,7 @@ "@testing-library/react": "^16.0.0", "@testing-library/user-event": "14.5.2", "@types/classnames": "^2.3.1", - "@types/dompurify": "^2.2.6", + "@types/dompurify": "^3.2.0", "@types/jest": "^29.5.13", "@types/lodash-es": "^4.17.8", "@types/react-dom": "^18.3.1", @@ -116,7 +116,7 @@ "react-dom": "^18", "react-router": "^7.0.2", "sass": "^1.78.0", - "dompurify": "^2.2.6", + "dompurify": "^3.2.3", "showdown": "^2.1.0", "classnames": "^2.2.6" }, From 630044c4a0fd15250d8b460aa60aedcafc5383df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:48:09 +0000 Subject: [PATCH 10/16] build(deps-dev): bump webpack from 5.96.1 to 5.97.1 in /clients/ui/frontend (#653) Bumps [webpack](https://github.com/webpack/webpack) from 5.96.1 to 5.97.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.96.1...v5.97.1) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- clients/ui/frontend/package-lock.json | 200 ++++++++++++-------------- clients/ui/frontend/package.json | 2 +- 2 files changed, 92 insertions(+), 110 deletions(-) diff --git a/clients/ui/frontend/package-lock.json b/clients/ui/frontend/package-lock.json index 71842ba3..de654c72 100644 --- a/clients/ui/frontend/package-lock.json +++ b/clients/ui/frontend/package-lock.json @@ -92,7 +92,7 @@ "tslib": "^2.7.0", "typescript": "^5.7.2", "url-loader": "^4.1.1", - "webpack": "^5.96.1", + "webpack": "^5.97.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.1.0", @@ -5075,163 +5075,148 @@ "optional": true }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true, - "license": "MIT" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true, - "license": "MIT" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true, - "license": "MIT" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true, - "license": "MIT" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, - "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true, - "license": "MIT" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -5286,15 +5271,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "license": "Apache-2.0" + "dev": true }, "node_modules/@zeit/schemas": { "version": "2.36.0", @@ -20536,17 +20519,16 @@ } }, "node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "version": "5.97.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", + "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "dev": true, - "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.14.0", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", diff --git a/clients/ui/frontend/package.json b/clients/ui/frontend/package.json index 075d02cf..889ffb82 100644 --- a/clients/ui/frontend/package.json +++ b/clients/ui/frontend/package.json @@ -95,7 +95,7 @@ "tslib": "^2.7.0", "typescript": "^5.7.2", "url-loader": "^4.1.1", - "webpack": "^5.96.1", + "webpack": "^5.97.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.1.0", From c22875e1284628c60a2bd2b1cc521f258bce8bc8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:00:09 +0000 Subject: [PATCH 11/16] build(deps-dev): bump webpack-dev-server from 5.1.0 to 5.2.0 in /clients/ui/frontend (#651) Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.1.0 to 5.2.0. - [Release notes](https://github.com/webpack/webpack-dev-server/releases) - [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.1.0...v5.2.0) --- updated-dependencies: - dependency-name: webpack-dev-server dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- clients/ui/frontend/package-lock.json | 93 +++++++-------------------- clients/ui/frontend/package.json | 2 +- 2 files changed, 26 insertions(+), 69 deletions(-) diff --git a/clients/ui/frontend/package-lock.json b/clients/ui/frontend/package-lock.json index de654c72..f85da266 100644 --- a/clients/ui/frontend/package-lock.json +++ b/clients/ui/frontend/package-lock.json @@ -95,7 +95,7 @@ "webpack": "^5.97.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.1.0", + "webpack-dev-server": "^5.2.0", "webpack-merge": "^6.0.1" }, "engines": { @@ -5638,8 +5638,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/array-includes": { "version": "3.1.8", @@ -6191,7 +6190,6 @@ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -6216,7 +6214,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6226,7 +6223,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6235,8 +6231,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/bonjour-service": { "version": "1.2.1", @@ -7232,7 +7227,6 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7262,7 +7256,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7271,8 +7264,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/copy-webpack-plugin": { "version": "12.0.2", @@ -8242,7 +8234,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8262,7 +8253,6 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -8647,7 +8637,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9643,7 +9632,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9736,11 +9724,10 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -9761,7 +9748,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -9776,6 +9763,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/content-disposition": { @@ -9783,7 +9774,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -9796,7 +9786,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9805,22 +9794,19 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "dev": true, - "license": "MIT" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true }, "node_modules/express/node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -10172,7 +10158,6 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", @@ -10191,7 +10176,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -10200,8 +10184,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -10516,7 +10499,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -10526,7 +10508,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11281,7 +11262,6 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, - "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -11409,7 +11389,6 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -14301,7 +14280,6 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -14339,7 +14317,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -14366,7 +14343,6 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -14390,7 +14366,6 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -16955,7 +16930,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -16969,7 +16943,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -17095,7 +17068,6 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -17111,7 +17083,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18062,7 +18033,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -18087,7 +18057,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -18096,15 +18065,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/send/node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18114,7 +18081,6 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -18309,7 +18275,6 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, - "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -18406,8 +18371,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/shallow-clone": { "version": "3.0.1", @@ -18802,7 +18766,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -19665,7 +19628,6 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.6" } @@ -20029,7 +19991,6 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -20242,7 +20203,6 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -20386,7 +20346,6 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -20735,11 +20694,10 @@ } }, "node_modules/webpack-dev-server": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.1.0.tgz", - "integrity": "sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.0.tgz", + "integrity": "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==", "dev": true, - "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -20754,10 +20712,9 @@ "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", - "express": "^4.19.2", + "express": "^4.21.2", "graceful-fs": "^4.2.6", - "html-entities": "^2.4.0", - "http-proxy-middleware": "^2.0.3", + "http-proxy-middleware": "^2.0.7", "ipaddr.js": "^2.1.0", "launch-editor": "^2.6.1", "open": "^10.0.3", diff --git a/clients/ui/frontend/package.json b/clients/ui/frontend/package.json index 889ffb82..e131fd12 100644 --- a/clients/ui/frontend/package.json +++ b/clients/ui/frontend/package.json @@ -98,7 +98,7 @@ "webpack": "^5.97.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.1.0", + "webpack-dev-server": "^5.2.0", "webpack-merge": "^6.0.1" }, "dependencies": { From 0938adb0d52519845464d766db9dc7c2ae667c7f Mon Sep 17 00:00:00 2001 From: Lucas Fernandez Date: Mon, 16 Dec 2024 15:18:08 +0100 Subject: [PATCH 12/16] Prepare dashboard for env variables (#645) Signed-off-by: lucferbux --- clients/ui/frontend/.env | 5 +++-- clients/ui/frontend/config/dotenv.js | 2 +- .../cypress/cypress/pages/appChrome.ts | 9 ++++----- .../cypress/support/commands/application.ts | 6 ++---- clients/ui/frontend/src/app/App.tsx | 17 +++++++---------- clients/ui/frontend/src/app/AppRoutes.tsx | 6 +++--- clients/ui/frontend/src/app/NavSidebar.tsx | 3 ++- clients/ui/frontend/src/app/hooks/useUser.ts | 10 ++++++++++ .../RegisterModel/useRegistrationCommonState.ts | 5 +++-- clients/ui/frontend/src/shared/api/apiUtils.ts | 10 ++-------- .../frontend/src/shared/hooks/useSettings.tsx | 6 ++---- .../src/shared/hooks/useTimeBasedRefresh.ts | 4 ++-- clients/ui/frontend/src/shared/types.ts | 4 ---- .../frontend/src/shared/utilities/appUtils.ts | 3 +++ .../ui/frontend/src/shared/utilities/const.ts | 16 ++++++++-------- 15 files changed, 52 insertions(+), 54 deletions(-) create mode 100644 clients/ui/frontend/src/app/hooks/useUser.ts create mode 100644 clients/ui/frontend/src/shared/utilities/appUtils.ts diff --git a/clients/ui/frontend/.env b/clients/ui/frontend/.env index 39fbc83c..cf90978c 100644 --- a/clients/ui/frontend/.env +++ b/clients/ui/frontend/.env @@ -1,9 +1,10 @@ IS_PROJECT_ROOT_DIR=false PORT=${FRONTEND_PORT} -########## Change the following three variables to customize the Dashboard ########## +########## Change the following variables to customize the Dashboard ########## LOGO=logo-light-theme.svg LOGO_DARK=logo-dark-theme.svg FAVICON=favicon.ico -PRODUCT_NAME=Model Registry +PRODUCT_NAME="Model Registry" +STYLE_THEME=mui-theme diff --git a/clients/ui/frontend/config/dotenv.js b/clients/ui/frontend/config/dotenv.js index c8a64d33..c0e765f7 100644 --- a/clients/ui/frontend/config/dotenv.js +++ b/clients/ui/frontend/config/dotenv.js @@ -159,7 +159,7 @@ const setupDotenvFilesForEnv = ({ env }) => { const OUTPUT_ONLY = process.env._OUTPUT_ONLY === 'true'; process.env._RELATIVE_DIRNAME = RELATIVE_DIRNAME; - process.env._UI_IS_PROJECT_ROOT_DIR = IS_ROOT; + process.env._IS_PROJECT_ROOT_DIR = IS_ROOT; process.env._IMAGES_DIRNAME = IMAGES_DIRNAME; process.env._PUBLIC_PATH = PUBLIC_PATH; process.env._SRC_DIR = SRC_DIR; diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/appChrome.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/appChrome.ts index 5d6afc32..903c3427 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/appChrome.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/appChrome.ts @@ -9,11 +9,10 @@ class AppChrome { cy.testA11y(); } - // TODO: [Auth-enablement] Uncomment once auth is enabled - // shouldBeUnauthorized() { - // cy.findByTestId('unauthorized-error'); - // return this; - // } + shouldBeUnauthorized() { + cy.findByTestId('unauthorized-error'); + return this; + } findNavToggle() { return cy.get('#page-nav-toggle'); diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/application.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/application.ts index c6100d0c..6a953ab1 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/application.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/application.ts @@ -1,13 +1,11 @@ import type { MatcherOptions } from '@testing-library/cypress'; import type { Matcher, MatcherOptions as DTLMatcherOptions } from '@testing-library/dom'; -// import type { UserAuthConfig } from '~/__tests__/cypress/cypress/types'; -// import { TEST_USER } from '~/__tests__/cypress/cypress/utils/e2eUsers'; /* eslint-disable @typescript-eslint/no-namespace */ declare global { namespace Cypress { interface Chainable { - // TODO: [Auth-enablement] Uncomment once auth is enabled + // TODO: [Global auth] Uncomment once auth is enabled // /** // * Visits the URL and performs a login if necessary. // * Uses credentials supplied by environment variables if not provided. @@ -121,7 +119,7 @@ declare global { } } -// TODO: [Auth-enablement] Uncomment once auth is enabled +// TODO: [Global auth] Uncomment once auth is enabled // Cypress.Commands.add('visitWithLogin', (url, user = TEST_USER) => { // if (Cypress.env('MOCK')) { // cy.visit(url); diff --git a/clients/ui/frontend/src/app/App.tsx b/clients/ui/frontend/src/app/App.tsx index 7510d690..66fc6967 100644 --- a/clients/ui/frontend/src/app/App.tsx +++ b/clients/ui/frontend/src/app/App.tsx @@ -13,7 +13,8 @@ import { } from '@patternfly/react-core'; import ToastNotifications from '~/shared/components/ToastNotifications'; import { useSettings } from '~/shared/hooks/useSettings'; -import { isMUITheme, Theme, USER_ID } from '~/shared/utilities/const'; +import { isMUITheme, Theme, AUTH_HEADER, DEV_MODE } from '~/shared/utilities/const'; +import { logout } from '~/shared/utilities/appUtils'; import NavSidebar from './NavSidebar'; import AppRoutes from './AppRoutes'; import { AppContext } from './AppContext'; @@ -40,12 +41,10 @@ const App: React.FC = () => { }, []); React.useEffect(() => { - // Add the user to localStorage if in PoC - // TODO: [Env Handling] Just add this logic in PoC mode - if (username) { - localStorage.setItem(USER_ID, username); + if (DEV_MODE && username) { + localStorage.setItem(AUTH_HEADER, username); } else { - localStorage.removeItem(USER_ID); + localStorage.removeItem(AUTH_HEADER); } }, [username]); @@ -76,9 +75,7 @@ const App: React.FC = () => { @@ -104,7 +101,7 @@ const App: React.FC = () => { { - //TODO: [Auth-enablement] Logout when auth is enabled + logout().then(() => window.location.reload()); }} /> } diff --git a/clients/ui/frontend/src/app/AppRoutes.tsx b/clients/ui/frontend/src/app/AppRoutes.tsx index 2e8b5f71..9c858d56 100644 --- a/clients/ui/frontend/src/app/AppRoutes.tsx +++ b/clients/ui/frontend/src/app/AppRoutes.tsx @@ -3,7 +3,7 @@ import { Navigate, Route, Routes } from 'react-router-dom'; import { NotFound } from './pages/notFound/NotFound'; import ModelRegistrySettingsRoutes from './pages/settings/ModelRegistrySettingsRoutes'; import ModelRegistryRoutes from './pages/modelRegistry/ModelRegistryRoutes'; -import { useAppContext } from './AppContext'; +import useUser from './hooks/useUser'; export const isNavDataGroup = (navItem: NavDataItem): navItem is NavDataGroup => 'children' in navItem; @@ -23,7 +23,7 @@ export type NavDataGroup = NavDataCommon & { type NavDataItem = NavDataHref | NavDataGroup; export const useAdminSettings = (): NavDataItem[] => { - const { clusterAdmin } = useAppContext().user; + const { clusterAdmin } = useUser(); if (!clusterAdmin) { return []; @@ -46,7 +46,7 @@ export const useNavData = (): NavDataItem[] => [ ]; const AppRoutes: React.FC = () => { - const { clusterAdmin } = useAppContext().user; + const { clusterAdmin } = useUser(); return ( diff --git a/clients/ui/frontend/src/app/NavSidebar.tsx b/clients/ui/frontend/src/app/NavSidebar.tsx index 80ed9c43..8af64a6f 100644 --- a/clients/ui/frontend/src/app/NavSidebar.tsx +++ b/clients/ui/frontend/src/app/NavSidebar.tsx @@ -9,6 +9,7 @@ import { PageSidebar, PageSidebarBody, } from '@patternfly/react-core'; +import { LOGO_LIGHT } from '~/shared/utilities/const'; import { useNavData, isNavDataGroup, NavDataHref, NavDataGroup } from './AppRoutes'; const NavHref: React.FC<{ item: NavDataHref }> = ({ item }) => ( @@ -50,7 +51,7 @@ const NavSidebar: React.FC = () => { diff --git a/clients/ui/frontend/src/app/hooks/useUser.ts b/clients/ui/frontend/src/app/hooks/useUser.ts new file mode 100644 index 00000000..5f4f60f7 --- /dev/null +++ b/clients/ui/frontend/src/app/hooks/useUser.ts @@ -0,0 +1,10 @@ +import { useContext } from 'react'; +import { UserSettings } from '~/shared/types'; +import { AppContext } from '~/app/AppContext'; + +const useUser = (): UserSettings => { + const { user } = useContext(AppContext); + return user; +}; + +export default useUser; diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/useRegistrationCommonState.ts b/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/useRegistrationCommonState.ts index 993616b2..fadde80c 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/useRegistrationCommonState.ts +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisterModel/useRegistrationCommonState.ts @@ -1,6 +1,7 @@ import React from 'react'; import { ModelRegistryContext } from '~/app/context/ModelRegistryContext'; import { ModelRegistryAPIState } from '~/app/context/useModelRegistryAPIState'; +import useUser from '~/app/hooks/useUser'; type RegistrationCommonState = { isSubmitting: boolean; @@ -17,7 +18,7 @@ export const useRegistrationCommonState = (): RegistrationCommonState => { const [submitError, setSubmitError] = React.useState(undefined); const { apiState } = React.useContext(ModelRegistryContext); - const author = 'kubeflow-user'; // TODO: [Auth-enablement] Enable this once we have users ---> useAppSelector((state) => state.user || ''); + const { userId } = useUser(); const handleSubmit = (doSubmit: () => Promise) => { setIsSubmitting(true); @@ -35,6 +36,6 @@ export const useRegistrationCommonState = (): RegistrationCommonState => { setSubmitError, handleSubmit, apiState, - author, + author: userId, }; }; diff --git a/clients/ui/frontend/src/shared/api/apiUtils.ts b/clients/ui/frontend/src/shared/api/apiUtils.ts index f6cfb7fa..01d03161 100644 --- a/clients/ui/frontend/src/shared/api/apiUtils.ts +++ b/clients/ui/frontend/src/shared/api/apiUtils.ts @@ -1,7 +1,7 @@ import { APIOptions } from '~/shared/api/types'; import { EitherOrNone } from '~/shared/typeHelpers'; import { ModelRegistryBody } from '~/app/types'; -import { USER_ID } from '~/shared/utilities/const'; +import { DEV_MODE, AUTH_HEADER } from '~/shared/utilities/const'; export const mergeRequestInit = ( opts: APIOptions = {}, @@ -65,17 +65,11 @@ const callRestJSON = ( requestData = JSON.stringify(data); } - // Get from the browser storage the value from the key USER_ID - // and set it as a header value for the request. - // THIS IS ONLY INTENEDED FOR THE POC WHEN YOU CANNOT INJECT IT WITH A PROXY - // TODO: [Env Handling] Just add it when in PoC - const userID = localStorage.getItem(USER_ID); - return fetch(`${host}${path}${searchParams ? `?${searchParams}` : ''}`, { ...otherOptions, headers: { ...otherOptions.headers, - ...(userID && { [USER_ID]: userID }), // TODO: [Env Handling] Just add it when in PoC + ...(DEV_MODE && { [AUTH_HEADER]: localStorage.getItem(AUTH_HEADER) }), ...(contentType && { 'Content-Type': contentType }), }, method, diff --git a/clients/ui/frontend/src/shared/hooks/useSettings.tsx b/clients/ui/frontend/src/shared/hooks/useSettings.tsx index c5d45ee9..d81488c6 100644 --- a/clients/ui/frontend/src/shared/hooks/useSettings.tsx +++ b/clients/ui/frontend/src/shared/hooks/useSettings.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { mockedUsername, POLL_INTERVAL, USER_ID } from '~/shared/utilities/const'; +import { USERNAME, POLL_INTERVAL, AUTH_HEADER, DEV_MODE } from '~/shared/utilities/const'; import { useDeepCompareMemoize } from '~/shared/utilities/useDeepCompareMemoize'; import { ConfigSettings, UserSettings } from '~/shared/types'; import useTimeBasedRefresh from '~/shared/hooks/useTimeBasedRefresh'; @@ -22,9 +22,7 @@ export const useSettings = (): { let watchHandle: ReturnType; let cancelled = false; const watchConfig = () => { - // TODO: [Env Handling] Add mocked mode for frontend in dev - // const headers = process.env.mocked === 'true' ? { [USER_ID]: mockedUsername } : undefined; - const headers = { [USER_ID]: mockedUsername }; + const headers = DEV_MODE ? { [AUTH_HEADER]: USERNAME } : undefined; Promise.all([fetchConfig(), userSettings({ headers })]) .then(([fetchedConfig, fetchedUser]) => { if (cancelled) { diff --git a/clients/ui/frontend/src/shared/hooks/useTimeBasedRefresh.ts b/clients/ui/frontend/src/shared/hooks/useTimeBasedRefresh.ts index 3ec4b296..f51a66a7 100644 --- a/clients/ui/frontend/src/shared/hooks/useTimeBasedRefresh.ts +++ b/clients/ui/frontend/src/shared/hooks/useTimeBasedRefresh.ts @@ -1,5 +1,6 @@ import * as React from 'react'; import { useBrowserStorage } from '~/shared/components/browserStorage'; +import { logout } from '~/shared/utilities/appUtils'; export type SetTime = (refreshDateMarker: Date) => void; @@ -33,8 +34,7 @@ const useTimeBasedRefresh = (): SetTime => { if (lastDate < refreshDateMarker) { setNewDateString(refreshDateMarker.toString()); console.log('Logging out and refreshing'); - // TODO: [Auth-enablement] Replace with actual logout function - //logout().then(() => window.location.reload()); + logout().then(() => window.location.reload()); } else { console.error( `We should have refreshed but it appears the last time we auto-refreshed was less than an hour ago. '${KEY_NAME}' session storage setting can be cleared for this to refresh again within the hour from the last refresh.`, diff --git a/clients/ui/frontend/src/shared/types.ts b/clients/ui/frontend/src/shared/types.ts index 394c1720..31658843 100644 --- a/clients/ui/frontend/src/shared/types.ts +++ b/clients/ui/frontend/src/shared/types.ts @@ -1,22 +1,18 @@ import { ValueOf } from '~/shared/typeHelpers'; -// TODO: [Data Flow] Get the status config params export type UserSettings = { userId: string; clusterAdmin?: boolean; }; -// TODO: [Data Flow] Add more config parameters export type ConfigSettings = { common: CommonConfig; }; -// TODO: [Data Flow] Add more config parameters export type CommonConfig = { featureFlags: FeatureFlag; }; -// TODO: [Data Flow] Add more config parameters export type FeatureFlag = { modelRegistry: boolean; }; diff --git a/clients/ui/frontend/src/shared/utilities/appUtils.ts b/clients/ui/frontend/src/shared/utilities/appUtils.ts new file mode 100644 index 00000000..84a622a0 --- /dev/null +++ b/clients/ui/frontend/src/shared/utilities/appUtils.ts @@ -0,0 +1,3 @@ +export const logout = (): Promise => + /* eslint-disable-next-line no-console */ + fetch('/oauth/sign_out').catch((err) => console.error('Error logging out', err)); diff --git a/clients/ui/frontend/src/shared/utilities/const.ts b/clients/ui/frontend/src/shared/utilities/const.ts index 5cc0a8a8..5fcb7e79 100644 --- a/clients/ui/frontend/src/shared/utilities/const.ts +++ b/clients/ui/frontend/src/shared/utilities/const.ts @@ -1,6 +1,3 @@ -// TODO: [Env Handling] Fetch the .env variable here. -const POLL_INTERVAL = 30000; - export enum Theme { Default = 'default-theme', MUI = 'mui-theme', @@ -9,9 +6,12 @@ export enum Theme { export const isMUITheme = (): boolean => STYLE_THEME === Theme.MUI; -export const STYLE_THEME = process.env.STYLE_THEME || Theme.MUI; - -export const USER_ID = 'kubeflow-userid'; -export const mockedUsername = 'user@example.com'; +const STYLE_THEME = process.env.STYLE_THEME || Theme.MUI; +const DEV_MODE = process.env.APP_ENV === 'development'; +const POLL_INTERVAL = process.env.POLL_INTERVAL ? parseInt(process.env.POLL_INTERVAL) : 30000; +const AUTH_HEADER = process.env.AUTH_HEADER || 'kubeflow-userid'; +const USERNAME = process.env.USERNAME || 'user@example.com'; +const IMAGE_DIR = process.env.IMAGE_DIR || 'images'; +const LOGO_LIGHT = process.env.LOGO || 'logo-light-theme.svg'; -export { POLL_INTERVAL }; +export { POLL_INTERVAL, DEV_MODE, AUTH_HEADER, USERNAME, IMAGE_DIR, LOGO_LIGHT }; From 1f7b9257889c189c4ef43810693dca8ed2c1e6a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:40:08 +0000 Subject: [PATCH 13/16] build(deps): bump helm/kind-action from 1.10.0 to 1.11.0 (#646) Bumps [helm/kind-action](https://github.com/helm/kind-action) from 1.10.0 to 1.11.0. - [Release notes](https://github.com/helm/kind-action/releases) - [Commits](https://github.com/helm/kind-action/compare/v1.10.0...v1.11.0) --- updated-dependencies: - dependency-name: helm/kind-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-image-pr.yml | 2 +- .github/workflows/csi-test.yml | 2 +- .github/workflows/python-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-image-pr.yml b/.github/workflows/build-image-pr.yml index 01b79ca4..5c98277e 100644 --- a/.github/workflows/build-image-pr.yml +++ b/.github/workflows/build-image-pr.yml @@ -34,7 +34,7 @@ jobs: IMG_VERSION: ${{ steps.tags.outputs.tag }} run: make image/build - name: Start Kind Cluster - uses: helm/kind-action@v1.10.0 + uses: helm/kind-action@v1.11.0 with: node_image: "kindest/node:v1.27.11" - name: Load Local Registry Test Image diff --git a/.github/workflows/csi-test.yml b/.github/workflows/csi-test.yml index 2221525f..275f779c 100644 --- a/.github/workflows/csi-test.yml +++ b/.github/workflows/csi-test.yml @@ -59,7 +59,7 @@ jobs: run: make image/build - name: Start KinD cluster - uses: helm/kind-action@v1.10.0 + uses: helm/kind-action@v1.11.0 with: node_image: "kindest/node:v1.27.11" diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 556143a9..cabe5b04 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -122,7 +122,7 @@ jobs: IMG_VERSION: ${{ steps.tags.outputs.tag }} run: make image/build - name: Start Kind Cluster - uses: helm/kind-action@v1.10.0 + uses: helm/kind-action@v1.11.0 with: node_image: "kindest/node:v1.27.11" cluster_name: chart-testing-py-${{ matrix.python }} From a861d083c34148b2bc369b6b83dd584d697e9d98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:41:08 +0000 Subject: [PATCH 14/16] build(deps-dev): bump ruff from 0.8.2 to 0.8.3 in /clients/python (#647) Bumps [ruff](https://github.com/astral-sh/ruff) from 0.8.2 to 0.8.3. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.8.2...0.8.3) --- updated-dependencies: - dependency-name: ruff dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- clients/python/poetry.lock | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/clients/python/poetry.lock b/clients/python/poetry.lock index 91ed4c79..08e71806 100644 --- a/clients/python/poetry.lock +++ b/clients/python/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -1615,29 +1615,29 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.8.2" +version = "0.8.3" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.8.2-py3-none-linux_armv6l.whl", hash = "sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d"}, - {file = "ruff-0.8.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5"}, - {file = "ruff-0.8.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f05cdf8d050b30e2ba55c9b09330b51f9f97d36d4673213679b965d25a785f3c"}, - {file = "ruff-0.8.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60f578c11feb1d3d257b2fb043ddb47501ab4816e7e221fbb0077f0d5d4e7b6f"}, - {file = "ruff-0.8.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbd5cf9b0ae8f30eebc7b360171bd50f59ab29d39f06a670b3e4501a36ba5897"}, - {file = "ruff-0.8.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b402ddee3d777683de60ff76da801fa7e5e8a71038f57ee53e903afbcefdaa58"}, - {file = "ruff-0.8.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:705832cd7d85605cb7858d8a13d75993c8f3ef1397b0831289109e953d833d29"}, - {file = "ruff-0.8.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32096b41aaf7a5cc095fa45b4167b890e4c8d3fd217603f3634c92a541de7248"}, - {file = "ruff-0.8.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e769083da9439508833cfc7c23e351e1809e67f47c50248250ce1ac52c21fb93"}, - {file = "ruff-0.8.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fe716592ae8a376c2673fdfc1f5c0c193a6d0411f90a496863c99cd9e2ae25d"}, - {file = "ruff-0.8.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:81c148825277e737493242b44c5388a300584d73d5774defa9245aaef55448b0"}, - {file = "ruff-0.8.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d261d7850c8367704874847d95febc698a950bf061c9475d4a8b7689adc4f7fa"}, - {file = "ruff-0.8.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1ca4e3a87496dc07d2427b7dd7ffa88a1e597c28dad65ae6433ecb9f2e4f022f"}, - {file = "ruff-0.8.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:729850feed82ef2440aa27946ab39c18cb4a8889c1128a6d589ffa028ddcfc22"}, - {file = "ruff-0.8.2-py3-none-win32.whl", hash = "sha256:ac42caaa0411d6a7d9594363294416e0e48fc1279e1b0e948391695db2b3d5b1"}, - {file = "ruff-0.8.2-py3-none-win_amd64.whl", hash = "sha256:2aae99ec70abf43372612a838d97bfe77d45146254568d94926e8ed5bbb409ea"}, - {file = "ruff-0.8.2-py3-none-win_arm64.whl", hash = "sha256:fb88e2a506b70cfbc2de6fae6681c4f944f7dd5f2fe87233a7233d888bad73e8"}, - {file = "ruff-0.8.2.tar.gz", hash = "sha256:b84f4f414dda8ac7f75075c1fa0b905ac0ff25361f42e6d5da681a465e0f78e5"}, + {file = "ruff-0.8.3-py3-none-linux_armv6l.whl", hash = "sha256:8d5d273ffffff0acd3db5bf626d4b131aa5a5ada1276126231c4174543ce20d6"}, + {file = "ruff-0.8.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e4d66a21de39f15c9757d00c50c8cdd20ac84f55684ca56def7891a025d7e939"}, + {file = "ruff-0.8.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c356e770811858bd20832af696ff6c7e884701115094f427b64b25093d6d932d"}, + {file = "ruff-0.8.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c0a60a825e3e177116c84009d5ebaa90cf40dfab56e1358d1df4e29a9a14b13"}, + {file = "ruff-0.8.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fb782f4db39501210ac093c79c3de581d306624575eddd7e4e13747e61ba18"}, + {file = "ruff-0.8.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f26bc76a133ecb09a38b7868737eded6941b70a6d34ef53a4027e83913b6502"}, + {file = "ruff-0.8.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:01b14b2f72a37390c1b13477c1c02d53184f728be2f3ffc3ace5b44e9e87b90d"}, + {file = "ruff-0.8.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53babd6e63e31f4e96ec95ea0d962298f9f0d9cc5990a1bbb023a6baf2503a82"}, + {file = "ruff-0.8.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ae441ce4cf925b7f363d33cd6570c51435972d697e3e58928973994e56e1452"}, + {file = "ruff-0.8.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7c65bc0cadce32255e93c57d57ecc2cca23149edd52714c0c5d6fa11ec328cd"}, + {file = "ruff-0.8.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5be450bb18f23f0edc5a4e5585c17a56ba88920d598f04a06bd9fd76d324cb20"}, + {file = "ruff-0.8.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8faeae3827eaa77f5721f09b9472a18c749139c891dbc17f45e72d8f2ca1f8fc"}, + {file = "ruff-0.8.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:db503486e1cf074b9808403991663e4277f5c664d3fe237ee0d994d1305bb060"}, + {file = "ruff-0.8.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6567be9fb62fbd7a099209257fef4ad2c3153b60579818b31a23c886ed4147ea"}, + {file = "ruff-0.8.3-py3-none-win32.whl", hash = "sha256:19048f2f878f3ee4583fc6cb23fb636e48c2635e30fb2022b3a1cd293402f964"}, + {file = "ruff-0.8.3-py3-none-win_amd64.whl", hash = "sha256:f7df94f57d7418fa7c3ffb650757e0c2b96cf2501a0b192c18e4fb5571dfada9"}, + {file = "ruff-0.8.3-py3-none-win_arm64.whl", hash = "sha256:fe2756edf68ea79707c8d68b78ca9a58ed9af22e430430491ee03e718b5e4936"}, + {file = "ruff-0.8.3.tar.gz", hash = "sha256:5e7558304353b84279042fc584a4f4cb8a07ae79b2bf3da1a7551d960b5626d3"}, ] [[package]] From 6c406123f36fd727052f4c586d9d6d4cfcb5f684 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:43:09 +0000 Subject: [PATCH 15/16] build(deps-dev): bump pytest-asyncio from 0.24.0 to 0.25.0 in /clients/python (#648) Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.24.0 to 0.25.0. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.24.0...v0.25.0) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- clients/python/poetry.lock | 12 ++++++------ clients/python/pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clients/python/poetry.lock b/clients/python/poetry.lock index 08e71806..1310f3b7 100644 --- a/clients/python/poetry.lock +++ b/clients/python/poetry.lock @@ -1484,20 +1484,20 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-asyncio" -version = "0.24.0" +version = "0.25.0" description = "Pytest support for asyncio" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b"}, - {file = "pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"}, + {file = "pytest_asyncio-0.25.0-py3-none-any.whl", hash = "sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3"}, + {file = "pytest_asyncio-0.25.0.tar.gz", hash = "sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609"}, ] [package.dependencies] pytest = ">=8.2,<9" [package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] @@ -2284,4 +2284,4 @@ hf = ["huggingface-hub"] [metadata] lock-version = "2.0" python-versions = ">= 3.9, < 4.0" -content-hash = "233d1d226ace1e5e881a363867f39f4b05b6e2dbed15c77ee69754bae0238e93" +content-hash = "dc63a589c45f8e27b1e54f471957e97ff241800786af0e62d1c004b7b6538c1c" diff --git a/clients/python/pyproject.toml b/clients/python/pyproject.toml index 654504b6..0ea44a74 100644 --- a/clients/python/pyproject.toml +++ b/clients/python/pyproject.toml @@ -46,7 +46,7 @@ coverage = { extras = ["toml"], version = "^7.3.2" } pytest-cov = ">=4.1,<7.0" ruff = ">=0.5.2,<0.9.0" mypy = "^1.7.0" -pytest-asyncio = ">=0.23.7,<0.25.0" +pytest-asyncio = ">=0.23.7,<0.26.0" requests = "^2.32.2" black = "^24.4.2" types-python-dateutil = "^2.9.0.20240906" From f56a1313679588422149e8cdf3fcdabd374da7a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:07:09 +0000 Subject: [PATCH 16/16] build(deps): bump golang.org/x/crypto from 0.26.0 to 0.31.0 (#643) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.26.0 to 0.31.0. - [Commits](https://github.com/golang/crypto/compare/v0.26.0...v0.31.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 062595f0..823874a6 100644 --- a/go.mod +++ b/go.mod @@ -78,10 +78,10 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/crypto v0.26.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/term v0.23.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/term v0.27.0 // indirect golang.org/x/time v0.5.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.171.0 // indirect @@ -149,8 +149,8 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index f167dd30..0851d86e 100644 --- a/go.sum +++ b/go.sum @@ -368,8 +368,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= @@ -414,8 +414,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -438,16 +438,16 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=