mirror of
https://github.com/usememos/memos.git
synced 2025-02-12 09:20:42 +01:00
chore: update memo related settings
This commit is contained in:
parent
0657a1ef5b
commit
4e54ec38ff
@ -46,6 +46,17 @@ func (s *APIV1Service) GetWorkspaceSetting(ctx context.Context, request *v1pb.Ge
|
|||||||
return nil, status.Errorf(codes.NotFound, "workspace setting not found")
|
return nil, status.Errorf(codes.NotFound, "workspace setting not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For storage setting, only host can get it.
|
||||||
|
if workspaceSetting.Key == storepb.WorkspaceSettingKey_STORAGE {
|
||||||
|
user, err := s.GetCurrentUser(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||||
|
}
|
||||||
|
if user == nil || user.Role != store.RoleHost {
|
||||||
|
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return convertWorkspaceSettingFromStore(workspaceSetting), nil
|
return convertWorkspaceSettingFromStore(workspaceSetting), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
web/src/components/Settings/MemoRelatedSettings.tsx
Normal file
81
web/src/components/Settings/MemoRelatedSettings.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { Button, Input, Switch } from "@mui/joy";
|
||||||
|
import { isEqual } from "lodash-es";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { WorkspaceSettingPrefix, useWorkspaceSettingStore } from "@/store/v1";
|
||||||
|
import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service";
|
||||||
|
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
|
||||||
|
import { useTranslate } from "@/utils/i18n";
|
||||||
|
|
||||||
|
const MemoRelatedSettings = () => {
|
||||||
|
const t = useTranslate();
|
||||||
|
const workspaceSettingStore = useWorkspaceSettingStore();
|
||||||
|
const originalSetting = WorkspaceMemoRelatedSetting.fromPartial(
|
||||||
|
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.MEMO_RELATED)?.memoRelatedSetting || {},
|
||||||
|
);
|
||||||
|
const [memoRelatedSetting, setMemoRelatedSetting] = useState<WorkspaceMemoRelatedSetting>(originalSetting);
|
||||||
|
|
||||||
|
const updatePartialSetting = (partial: Partial<WorkspaceMemoRelatedSetting>) => {
|
||||||
|
const newWorkspaceMemoRelatedSetting = WorkspaceMemoRelatedSetting.fromPartial({
|
||||||
|
...memoRelatedSetting,
|
||||||
|
...partial,
|
||||||
|
});
|
||||||
|
setMemoRelatedSetting(newWorkspaceMemoRelatedSetting);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSetting = async () => {
|
||||||
|
await workspaceSettingStore.setWorkspaceSetting({
|
||||||
|
name: `${WorkspaceSettingPrefix}${WorkspaceSettingKey.MEMO_RELATED}`,
|
||||||
|
memoRelatedSetting,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full flex flex-col gap-2 pt-2 pb-4">
|
||||||
|
<p className="font-medium text-gray-700 dark:text-gray-500">Memo related settings</p>
|
||||||
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
|
<span>{t("setting.system-section.disable-public-memos")}</span>
|
||||||
|
<Switch
|
||||||
|
checked={memoRelatedSetting.disallowPublicVisible}
|
||||||
|
onChange={(event) => updatePartialSetting({ disallowPublicVisible: event.target.checked })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
|
<span>{t("setting.system-section.display-with-updated-time")}</span>
|
||||||
|
<Switch
|
||||||
|
checked={memoRelatedSetting.displayWithUpdateTime}
|
||||||
|
onChange={(event) => updatePartialSetting({ displayWithUpdateTime: event.target.checked })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
|
<span>{t("setting.system-section.enable-auto-compact")}</span>
|
||||||
|
<Switch
|
||||||
|
checked={memoRelatedSetting.enableAutoCompact}
|
||||||
|
onChange={(event) => updatePartialSetting({ enableAutoCompact: event.target.checked })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
|
<span>{t("setting.system-section.enable-double-click-to-edit")}</span>
|
||||||
|
<Switch
|
||||||
|
checked={memoRelatedSetting.enableDoubleClickEdit}
|
||||||
|
onChange={(event) => updatePartialSetting({ enableDoubleClickEdit: event.target.checked })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
|
<span>Content length limit(Byte)</span>
|
||||||
|
<Input
|
||||||
|
className="w-24"
|
||||||
|
type="number"
|
||||||
|
defaultValue={memoRelatedSetting.contentLengthLimit}
|
||||||
|
onBlur={(event) => updatePartialSetting({ contentLengthLimit: Number(event.target.value) })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 w-full flex justify-end">
|
||||||
|
<Button disabled={isEqual(memoRelatedSetting, originalSetting)} onClick={updateSetting}>
|
||||||
|
{t("common.save")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MemoRelatedSettings;
|
@ -1,10 +1,10 @@
|
|||||||
import { Button, Divider, Input, Switch, Textarea } from "@mui/joy";
|
import { Button, Switch, Textarea } from "@mui/joy";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { workspaceSettingServiceClient } from "@/grpcweb";
|
import { workspaceSettingServiceClient } from "@/grpcweb";
|
||||||
import { WorkspaceSettingPrefix, useWorkspaceSettingStore } from "@/store/v1";
|
import { WorkspaceSettingPrefix, useWorkspaceSettingStore } from "@/store/v1";
|
||||||
import { WorkspaceGeneralSetting, WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service";
|
import { WorkspaceGeneralSetting } from "@/types/proto/api/v1/workspace_setting_service";
|
||||||
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
|
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
|
||||||
import { useTranslate } from "@/utils/i18n";
|
import { useTranslate } from "@/utils/i18n";
|
||||||
import { showCommonDialog } from "../Dialog/CommonDialog";
|
import { showCommonDialog } from "../Dialog/CommonDialog";
|
||||||
@ -17,11 +17,6 @@ const WorkspaceSection = () => {
|
|||||||
const [workspaceGeneralSetting, setWorkspaceGeneralSetting] = useState<WorkspaceGeneralSetting>(
|
const [workspaceGeneralSetting, setWorkspaceGeneralSetting] = useState<WorkspaceGeneralSetting>(
|
||||||
WorkspaceGeneralSetting.fromPartial(workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.GENERAL)?.generalSetting || {}),
|
WorkspaceGeneralSetting.fromPartial(workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.GENERAL)?.generalSetting || {}),
|
||||||
);
|
);
|
||||||
const [workspaceMemoRelatedSetting, setWorkspaceMemoRelatedSetting] = useState<WorkspaceMemoRelatedSetting>(
|
|
||||||
WorkspaceMemoRelatedSetting.fromPartial(
|
|
||||||
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.MEMO_RELATED)?.memoRelatedSetting || {},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleAllowSignUpChanged = async (value: boolean) => {
|
const handleAllowSignUpChanged = async (value: boolean) => {
|
||||||
const setting = { ...workspaceGeneralSetting, disallowSignup: !value };
|
const setting = { ...workspaceGeneralSetting, disallowSignup: !value };
|
||||||
@ -104,56 +99,6 @@ const WorkspaceSection = () => {
|
|||||||
toast.success(t("message.update-succeed"));
|
toast.success(t("message.update-succeed"));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDisablePublicMemosChanged = async (value: boolean) => {
|
|
||||||
const update: WorkspaceMemoRelatedSetting = { ...workspaceMemoRelatedSetting, disallowPublicVisible: value };
|
|
||||||
setWorkspaceMemoRelatedSetting(update);
|
|
||||||
await workspaceSettingStore.setWorkspaceSetting({
|
|
||||||
name: `${WorkspaceSettingPrefix}${WorkspaceSettingKey.MEMO_RELATED}`,
|
|
||||||
memoRelatedSetting: update,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMemoDisplayWithUpdatedTs = async (value: boolean) => {
|
|
||||||
const update: WorkspaceMemoRelatedSetting = { ...workspaceMemoRelatedSetting, displayWithUpdateTime: value };
|
|
||||||
setWorkspaceMemoRelatedSetting(update);
|
|
||||||
await workspaceSettingStore.setWorkspaceSetting({
|
|
||||||
name: `${WorkspaceSettingPrefix}${WorkspaceSettingKey.MEMO_RELATED}`,
|
|
||||||
memoRelatedSetting: update,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMemoEnableAutoCompact = async (value: boolean) => {
|
|
||||||
const update: WorkspaceMemoRelatedSetting = { ...workspaceMemoRelatedSetting, enableAutoCompact: value };
|
|
||||||
setWorkspaceMemoRelatedSetting(update);
|
|
||||||
await workspaceSettingStore.setWorkspaceSetting({
|
|
||||||
name: `${WorkspaceSettingPrefix}${WorkspaceSettingKey.MEMO_RELATED}`,
|
|
||||||
memoRelatedSetting: update,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMemoEnableDoubleClickToEdit = async (value: boolean) => {
|
|
||||||
const update: WorkspaceMemoRelatedSetting = { ...workspaceMemoRelatedSetting, enableDoubleClickEdit: value };
|
|
||||||
setWorkspaceMemoRelatedSetting(update);
|
|
||||||
await workspaceSettingStore.setWorkspaceSetting({
|
|
||||||
name: `${WorkspaceSettingPrefix}${WorkspaceSettingKey.MEMO_RELATED}`,
|
|
||||||
memoRelatedSetting: update,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMemoContentLengthLimitChanges = async (value: number) => {
|
|
||||||
if (value < 8 * 1024) {
|
|
||||||
toast.error("Content length limit should be greater than 8KB");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const update: WorkspaceMemoRelatedSetting = { ...workspaceMemoRelatedSetting, contentLengthLimit: value };
|
|
||||||
setWorkspaceMemoRelatedSetting(update);
|
|
||||||
await workspaceSettingStore.setWorkspaceSetting({
|
|
||||||
name: `${WorkspaceSettingPrefix}${WorkspaceSettingKey.MEMO_RELATED}`,
|
|
||||||
memoRelatedSetting: update,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full flex flex-col gap-2 pt-2 pb-4">
|
<div className="w-full flex flex-col gap-2 pt-2 pb-4">
|
||||||
<p className="font-medium text-gray-700 dark:text-gray-500">{t("common.basic")}</p>
|
<p className="font-medium text-gray-700 dark:text-gray-500">{t("common.basic")}</p>
|
||||||
@ -225,45 +170,6 @@ const WorkspaceSection = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Divider className="!my-3" />
|
|
||||||
<p className="font-medium text-gray-700 dark:text-gray-500">Memo related settings</p>
|
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
|
||||||
<span>{t("setting.system-section.disable-public-memos")}</span>
|
|
||||||
<Switch
|
|
||||||
checked={workspaceMemoRelatedSetting.disallowPublicVisible}
|
|
||||||
onChange={(event) => handleDisablePublicMemosChanged(event.target.checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
|
||||||
<span>{t("setting.system-section.display-with-updated-time")}</span>
|
|
||||||
<Switch
|
|
||||||
checked={workspaceMemoRelatedSetting.displayWithUpdateTime}
|
|
||||||
onChange={(event) => handleMemoDisplayWithUpdatedTs(event.target.checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
|
||||||
<span>{t("setting.system-section.enable-auto-compact")}</span>
|
|
||||||
<Switch
|
|
||||||
checked={workspaceMemoRelatedSetting.enableAutoCompact}
|
|
||||||
onChange={(event) => handleMemoEnableAutoCompact(event.target.checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
|
||||||
<span>{t("setting.system-section.enable-double-click-to-edit")}</span>
|
|
||||||
<Switch
|
|
||||||
checked={workspaceMemoRelatedSetting.enableDoubleClickEdit}
|
|
||||||
onChange={(event) => handleMemoEnableDoubleClickToEdit(event.target.checked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
|
||||||
<span>Content length limit(Byte)</span>
|
|
||||||
<Input
|
|
||||||
className="w-32"
|
|
||||||
type="number"
|
|
||||||
defaultValue={workspaceMemoRelatedSetting.contentLengthLimit}
|
|
||||||
onBlur={(event) => handleMemoContentLengthLimitChanges(Number(event.target.value))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -297,7 +297,8 @@
|
|||||||
"max-upload-size": "Maximum upload size (MiB)",
|
"max-upload-size": "Maximum upload size (MiB)",
|
||||||
"max-upload-size-hint": "Recommended value is 32 MiB.",
|
"max-upload-size-hint": "Recommended value is 32 MiB.",
|
||||||
"server-name": "Server Name"
|
"server-name": "Server Name"
|
||||||
}
|
},
|
||||||
|
"memo-related": "Memo"
|
||||||
},
|
},
|
||||||
"tag": {
|
"tag": {
|
||||||
"all-tags": "All Tags",
|
"all-tags": "All Tags",
|
||||||
|
@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|||||||
import Icon from "@/components/Icon";
|
import Icon from "@/components/Icon";
|
||||||
import MobileHeader from "@/components/MobileHeader";
|
import MobileHeader from "@/components/MobileHeader";
|
||||||
import MemberSection from "@/components/Settings/MemberSection";
|
import MemberSection from "@/components/Settings/MemberSection";
|
||||||
|
import MemoRelatedSettings from "@/components/Settings/MemoRelatedSettings";
|
||||||
import MyAccountSection from "@/components/Settings/MyAccountSection";
|
import MyAccountSection from "@/components/Settings/MyAccountSection";
|
||||||
import PreferencesSection from "@/components/Settings/PreferencesSection";
|
import PreferencesSection from "@/components/Settings/PreferencesSection";
|
||||||
import SSOSection from "@/components/Settings/SSOSection";
|
import SSOSection from "@/components/Settings/SSOSection";
|
||||||
@ -17,19 +18,20 @@ import { User_Role } from "@/types/proto/api/v1/user_service";
|
|||||||
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
|
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
|
||||||
import { useTranslate } from "@/utils/i18n";
|
import { useTranslate } from "@/utils/i18n";
|
||||||
|
|
||||||
type SettingSection = "my-account" | "preference" | "member" | "system" | "storage" | "sso";
|
type SettingSection = "my-account" | "preference" | "member" | "system" | "memo-related" | "storage" | "sso";
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
selectedSection: SettingSection;
|
selectedSection: SettingSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BASIC_SECTIONS: SettingSection[] = ["my-account", "preference"];
|
const BASIC_SECTIONS: SettingSection[] = ["my-account", "preference"];
|
||||||
const ADMIN_SECTIONS: SettingSection[] = ["member", "system", "storage", "sso"];
|
const ADMIN_SECTIONS: SettingSection[] = ["member", "system", "memo-related", "storage", "sso"];
|
||||||
const SECTION_ICON_MAP: Record<SettingSection, LucideIcon> = {
|
const SECTION_ICON_MAP: Record<SettingSection, LucideIcon> = {
|
||||||
"my-account": Icon.User,
|
"my-account": Icon.User,
|
||||||
preference: Icon.Cog,
|
preference: Icon.Cog,
|
||||||
member: Icon.Users,
|
member: Icon.Users,
|
||||||
system: Icon.Settings2,
|
system: Icon.Settings2,
|
||||||
|
"memo-related": Icon.Library,
|
||||||
storage: Icon.Database,
|
storage: Icon.Database,
|
||||||
sso: Icon.Key,
|
sso: Icon.Key,
|
||||||
};
|
};
|
||||||
@ -125,6 +127,8 @@ const Setting = () => {
|
|||||||
<MemberSection />
|
<MemberSection />
|
||||||
) : state.selectedSection === "system" ? (
|
) : state.selectedSection === "system" ? (
|
||||||
<WorkspaceSection />
|
<WorkspaceSection />
|
||||||
|
) : state.selectedSection === "memo-related" ? (
|
||||||
|
<MemoRelatedSettings />
|
||||||
) : state.selectedSection === "storage" ? (
|
) : state.selectedSection === "storage" ? (
|
||||||
<StorageSection />
|
<StorageSection />
|
||||||
) : state.selectedSection === "sso" ? (
|
) : state.selectedSection === "sso" ? (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user