From 7e35d3a3197ebf20058bbdc4f0780a82b6e288b9 Mon Sep 17 00:00:00 2001 From: Steven Date: Sun, 18 Aug 2024 08:43:47 +0800 Subject: [PATCH] feat: add security setting section --- .../WorkspaceGeneralSettingSection.tsx | 7 +- .../setting/WorkspaceSecuritySection.tsx | 67 +++++++++++++++++++ frontend/web/src/pages/WorkspaceSetting.tsx | 3 + frontend/web/src/stores/workspace.ts | 1 + server/route/api/v1/workspace_service.go | 17 +++++ 5 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 frontend/web/src/components/setting/WorkspaceSecuritySection.tsx diff --git a/frontend/web/src/components/setting/WorkspaceGeneralSettingSection.tsx b/frontend/web/src/components/setting/WorkspaceGeneralSettingSection.tsx index bb49f07..af67c0b 100644 --- a/frontend/web/src/components/setting/WorkspaceGeneralSettingSection.tsx +++ b/frontend/web/src/components/setting/WorkspaceGeneralSettingSection.tsx @@ -1,4 +1,4 @@ -import { Button, Divider, Option, Select, Textarea } from "@mui/joy"; +import { Button, Option, Select, Textarea } from "@mui/joy"; import { head, isEqual } from "lodash-es"; import { useRef, useState } from "react"; import toast from "react-hot-toast"; @@ -10,7 +10,6 @@ import { Visibility } from "@/types/proto/api/v1/common"; import { WorkspaceSetting } from "@/types/proto/api/v1/workspace_service"; import FeatureBadge from "../FeatureBadge"; import Icon from "../Icon"; -import SSOSection from "./SSOSection"; const getDefaultVisibility = (visibility?: Visibility) => { if (!visibility || [Visibility.VISIBILITY_UNSPECIFIED, Visibility.UNRECOGNIZED].includes(visibility)) { @@ -157,10 +156,6 @@ const WorkspaceGeneralSettingSection = () => { {t("common.save")} - - - - ); diff --git a/frontend/web/src/components/setting/WorkspaceSecuritySection.tsx b/frontend/web/src/components/setting/WorkspaceSecuritySection.tsx new file mode 100644 index 0000000..b8095e4 --- /dev/null +++ b/frontend/web/src/components/setting/WorkspaceSecuritySection.tsx @@ -0,0 +1,67 @@ +import { Switch } from "@mui/joy"; +import toast from "react-hot-toast"; +import { workspaceServiceClient } from "@/grpcweb"; +import { useWorkspaceStore } from "@/stores"; +import { WorkspaceSetting } from "@/types/proto/api/v1/workspace_service"; +import SSOSection from "./SSOSection"; + +const WorkspaceSecuritySection = () => { + const workspaceStore = useWorkspaceStore(); + + const toggleDisallowUserRegistration = async (on: boolean) => { + if (on) { + const confirmed = window.confirm("Are you sure to disallow user registration? This will prevent new users from signing up."); + if (!confirmed) { + return; + } + } + + await updateWorkspaceSetting( + WorkspaceSetting.fromPartial({ + disallowUserRegistration: on, + }), + ["disallow_user_registration"], + ); + }; + + const updateWorkspaceSetting = async (workspaceSetting: WorkspaceSetting, updateMask: string[]) => { + if (updateMask.length === 0) { + toast.error("No changes made"); + return; + } + + console.log("1", { + setting: workspaceSetting, + updateMask: updateMask, + }); + try { + await workspaceServiceClient.updateWorkspaceSetting({ + setting: workspaceSetting, + updateMask: updateMask, + }); + await workspaceStore.fetchWorkspaceSetting(); + toast.success("Workspace setting saved successfully"); + } catch (error: any) { + toast.error(error.details); + } + }; + + return ( +
+

Security

+
+ +
+ toggleDisallowUserRegistration(event.target.checked)} + endDecorator={Disallow user registration} + /> +
+
+
+ ); +}; + +export default WorkspaceSecuritySection; diff --git a/frontend/web/src/pages/WorkspaceSetting.tsx b/frontend/web/src/pages/WorkspaceSetting.tsx index 27254f2..70cdd8b 100644 --- a/frontend/web/src/pages/WorkspaceSetting.tsx +++ b/frontend/web/src/pages/WorkspaceSetting.tsx @@ -4,6 +4,7 @@ import { Link } from "react-router-dom"; import Icon from "@/components/Icon"; import WorkspaceGeneralSettingSection from "@/components/setting/WorkspaceGeneralSettingSection"; import WorkspaceMembersSection from "@/components/setting/WorkspaceMembersSection"; +import WorkspaceSecuritySection from "@/components/setting/WorkspaceSecuritySection"; import { useUserStore, useWorkspaceStore } from "@/stores"; import { stringifyPlanType } from "@/stores/subscription"; import { Role } from "@/types/proto/api/v1/user_service"; @@ -44,6 +45,8 @@ const WorkspaceSetting = () => { + + ); }; diff --git a/frontend/web/src/stores/workspace.ts b/frontend/web/src/stores/workspace.ts index b1f278e..3dc1ce8 100644 --- a/frontend/web/src/stores/workspace.ts +++ b/frontend/web/src/stores/workspace.ts @@ -7,6 +7,7 @@ export enum FeatureType { SSO = "ysh.slash.sso", AdvancedAnalytics = "ysh.slash.advanced-analytics", UnlimitedAccounts = "ysh.slash.unlimited-accounts", + UnlimitedShortcuts = "ysh.slash.unlimited-shortcuts", UnlimitedCollections = "ysh.slash.unlimited-collections", CustomeBranding = "ysh.slash.custom-branding", } diff --git a/server/route/api/v1/workspace_service.go b/server/route/api/v1/workspace_service.go index 2b61a2c..1e8e3bf 100644 --- a/server/route/api/v1/workspace_service.go +++ b/server/route/api/v1/workspace_service.go @@ -61,6 +61,9 @@ func (s *APIV1Service) GetWorkspaceSetting(ctx context.Context, _ *v1pb.GetWorks generalSetting := v.GetGeneral() workspaceSetting.Branding = generalSetting.GetBranding() workspaceSetting.CustomStyle = generalSetting.GetCustomStyle() + } else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SECURITY { + securitySetting := v.GetSecurity() + workspaceSetting.DisallowUserRegistration = securitySetting.GetDisallowUserRegistration() } else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SHORTCUT_RELATED { shortcutRelatedSetting := v.GetShortcutRelated() workspaceSetting.DefaultVisibility = v1pb.Visibility(shortcutRelatedSetting.GetDefaultVisibility()) @@ -153,6 +156,20 @@ func (s *APIV1Service) UpdateWorkspaceSetting(ctx context.Context, request *v1pb }); err != nil { return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err) } + } else if path == "disallow_user_registration" { + securitySetting, err := s.Store.GetWorkspaceSecuritySetting(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get workspace setting: %v", err) + } + securitySetting.DisallowUserRegistration = request.Setting.DisallowUserRegistration + if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{ + Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SECURITY, + Value: &storepb.WorkspaceSetting_Security{ + Security: securitySetting, + }, + }); err != nil { + return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err) + } } else { return nil, status.Errorf(codes.InvalidArgument, "invalid path: %s", path) }