fix(web): convert enum values to string names in API resource paths

Frontend was incorrectly using numeric enum values (e.g., 1, 2, 3) instead
of string names (e.g., "GENERAL", "STORAGE") when constructing API resource
paths. This caused the backend to fail with "unsupported instance setting
key: INSTANCE_SETTING_KEY_UNSPECIFIED" errors during initialization.

Changes:
- Add helper functions in store/common.ts to convert enum values to names
  - getInstanceSettingKeyName() and buildInstanceSettingName()
  - getUserSettingKeyName() and buildUserSettingName()
- Update instance store to use string enum names in API calls
- Update user store to use string enum names in API calls
- Update all components to use new helper functions for setting names

Fixes enum string conversion for:
- InstanceSetting_Key (6 locations)
- UserSetting_Key (2 locations)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Steven 2025-12-11 20:08:11 +08:00
parent edd3ced9bf
commit 8a7e00886d
7 changed files with 41 additions and 15 deletions

View File

@ -10,7 +10,7 @@ import { Textarea } from "@/components/ui/textarea";
import { identityProviderServiceClient } from "@/grpcweb";
import useDialog from "@/hooks/useDialog";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import { buildInstanceSettingName } from "@/store/common";
import { IdentityProvider } from "@/types/proto/api/v1/idp_service_pb";
import {
InstanceSetting_GeneralSetting,
@ -63,7 +63,7 @@ const InstanceSection = observer(() => {
try {
await instanceStore.upsertInstanceSetting(
create(InstanceSettingSchema, {
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.GENERAL}`,
name: buildInstanceSettingName(InstanceSetting_Key.GENERAL),
value: {
case: "generalSetting",
value: instanceGeneralSetting,

View File

@ -9,7 +9,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import { buildInstanceSettingName } from "@/store/common";
import {
InstanceSetting_Key,
InstanceSetting_MemoRelatedSetting,
@ -63,7 +63,7 @@ const MemoRelatedSettings = observer(() => {
try {
await instanceStore.upsertInstanceSetting(
create(InstanceSettingSchema, {
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.MEMO_RELATED}`,
name: buildInstanceSettingName(InstanceSetting_Key.MEMO_RELATED),
value: {
case: "memoRelatedSetting",
value: memoRelatedSetting,

View File

@ -9,7 +9,7 @@ import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Switch } from "@/components/ui/switch";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import { buildInstanceSettingName } from "@/store/common";
import {
InstanceSetting_Key,
InstanceSetting_StorageSetting,
@ -154,7 +154,7 @@ const StorageSection = observer(() => {
const saveInstanceStorageSetting = async () => {
await instanceStore.upsertInstanceSetting(
create(InstanceSettingSchema, {
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.STORAGE}`,
name: buildInstanceSettingName(InstanceSetting_Key.STORAGE),
value: {
case: "storageSetting",
value: instanceStorageSetting,

View File

@ -7,7 +7,7 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import { buildInstanceSettingName } from "@/store/common";
import {
InstanceSetting_GeneralSetting_CustomProfile,
InstanceSetting_GeneralSetting_CustomProfileSchema,
@ -78,7 +78,7 @@ function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }: Props)
try {
await instanceStore.upsertInstanceSetting(
create(InstanceSettingSchema, {
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.GENERAL}`,
name: buildInstanceSettingName(InstanceSetting_Key.GENERAL),
value: {
case: "generalSetting",
value: {

View File

@ -1,3 +1,6 @@
import { InstanceSetting_Key } from "@/types/proto/api/v1/instance_service_pb";
import { UserSetting_Key } from "@/types/proto/api/v1/user_service_pb";
export const instanceSettingNamePrefix = "instance/settings/";
export const userNamePrefix = "users/";
export const memoNamePrefix = "memos/";
@ -15,3 +18,25 @@ export const extractMemoIdFromName = (name: string) => {
export const extractIdentityProviderIdFromName = (name: string) => {
return parseInt(name.split(identityProviderNamePrefix).pop() || "", 10);
};
// Helper function to convert InstanceSetting_Key enum value to string name
export const getInstanceSettingKeyName = (key: InstanceSetting_Key): string => {
// TypeScript enum reverse mapping: converts numeric value to string name
return InstanceSetting_Key[key];
};
// Helper function to build instance setting name from key
export const buildInstanceSettingName = (key: InstanceSetting_Key): string => {
return `${instanceSettingNamePrefix}${getInstanceSettingKeyName(key)}`;
};
// Helper function to convert UserSetting_Key enum value to string name
export const getUserSettingKeyName = (key: UserSetting_Key): string => {
// TypeScript enum reverse mapping: converts numeric value to string name
return UserSetting_Key[key];
};
// Helper function to build user setting name from username and key
export const buildUserSettingName = (username: string, key: UserSetting_Key): string => {
return `${username}/settings/${getUserSettingKeyName(key)}`;
};

View File

@ -15,7 +15,7 @@ import {
InstanceSettingSchema,
} from "@/types/proto/api/v1/instance_service_pb";
import { createServerStore, StandardState } from "./base-store";
import { instanceSettingNamePrefix } from "./common";
import { buildInstanceSettingName, getInstanceSettingKeyName, instanceSettingNamePrefix } from "./common";
import { createRequestKey } from "./store-utils";
class InstanceState extends StandardState {
@ -25,7 +25,7 @@ class InstanceState extends StandardState {
// Computed property for general settings (memoized)
get generalSetting(): InstanceSetting_GeneralSetting {
return computed(() => {
const setting = this.settings.find((s) => s.name === `${instanceSettingNamePrefix}${InstanceSetting_Key.GENERAL}`);
const setting = this.settings.find((s) => s.name === `${instanceSettingNamePrefix}GENERAL`);
if (setting?.value.case === "generalSetting") {
return setting.value.value;
}
@ -36,7 +36,7 @@ class InstanceState extends StandardState {
// Computed property for memo-related settings (memoized)
get memoRelatedSetting(): InstanceSetting_MemoRelatedSetting {
return computed(() => {
const setting = this.settings.find((s) => s.name === `${instanceSettingNamePrefix}${InstanceSetting_Key.MEMO_RELATED}`);
const setting = this.settings.find((s) => s.name === `${instanceSettingNamePrefix}MEMO_RELATED`);
if (setting?.value.case === "memoRelatedSetting") {
return setting.value.value;
}
@ -60,7 +60,7 @@ const instanceStore = (() => {
requestKey,
async () => {
const setting = await instanceServiceClient.getInstanceSetting({
name: `${instanceSettingNamePrefix}${settingKey}`,
name: buildInstanceSettingName(settingKey),
});
// Merge into settings array, avoiding duplicates
@ -88,7 +88,7 @@ const instanceStore = (() => {
};
const getInstanceSettingByKey = (settingKey: InstanceSetting_Key): InstanceSetting => {
const setting = state.settings.find((s) => s.name === `${instanceSettingNamePrefix}${settingKey}`);
const setting = state.settings.find((s) => s.name === buildInstanceSettingName(settingKey));
return setting || create(InstanceSettingSchema, {});
};

View File

@ -16,6 +16,7 @@ import {
UserSettingSchema,
UserStats,
} from "@/types/proto/api/v1/user_service_pb";
import { buildUserSettingName } from "./common";
import { createRequestKey, RequestDeduplicator, StoreError } from "./store-utils";
// Helper to extract setting value from UserSetting oneof
@ -164,7 +165,7 @@ const userStore = (() => {
throw new Error("No current user");
}
const settingName = `${state.currentUser}/settings/${UserSetting_Key.GENERAL}`;
const settingName = buildUserSettingName(state.currentUser, UserSetting_Key.GENERAL);
const userSetting = create(UserSettingSchema, {
name: settingName,
value: {
@ -188,7 +189,7 @@ const userStore = (() => {
throw new Error("No current user");
}
const settingName = `${state.currentUser}/settings/${UserSetting_Key.GENERAL}`;
const settingName = buildUserSettingName(state.currentUser, UserSetting_Key.GENERAL);
const userSetting = await userServiceClient.getUserSetting({ name: settingName });
const generalSetting = getSettingValue<UserSetting_GeneralSetting>(userSetting, "generalSetting");