fix(workspace): keep workspace ids as strings so a switch survives reload

This commit is contained in:
matevip 2026-05-19 20:06:56 +08:00
parent 651d53050e
commit 92d35a3d3d
5 changed files with 21 additions and 16 deletions

View File

@ -87,7 +87,7 @@ export const authApi = {
http.post('/auth/login', data),
listUsers: () => http.get('/auth/users'),
createUser: (data: any) => http.post('/auth/users', data),
changePassword: (id: number, oldPassword: string, newPassword: string) =>
changePassword: (id: string | number, oldPassword: string, newPassword: string) =>
http.put(`/auth/users/${id}/password`, null, { params: { oldPassword, newPassword } }),
}
@ -953,7 +953,7 @@ export const hotCacheApi = {
export interface WorkflowSummary {
id: number
workspaceId: number
workspaceId: string | number
name: string
description?: string
enabled: boolean
@ -985,7 +985,7 @@ export interface WorkflowRun {
id: number
workflowId: number
revisionId: number
workspaceId: number
workspaceId: string | number
state: string
triggeredBy?: string
initialInputRef?: string
@ -1048,7 +1048,7 @@ export interface ResumeResponse {
}
export const workflowApi = {
list: (workspaceId: number) =>
list: (workspaceId: string | number) =>
http.get<WorkflowSummary[]>('/workflows', { params: { workspaceId } }),
get: (id: number) => http.get<WorkflowSummary>(`/workflows/${id}`),
create: (data: Partial<WorkflowSummary>) =>
@ -1119,7 +1119,7 @@ export interface WorkflowDraftTemplate {
export interface TriggerSummary {
id: number
workspaceId: number
workspaceId: string | number
name?: string
patternType: string
patternJson: string
@ -1149,7 +1149,7 @@ export interface TriggerSummary {
}
export const triggerApi = {
list: (workspaceId: number) =>
list: (workspaceId: string | number) =>
http.get<TriggerSummary[]>('/triggers', { params: { workspaceId } }),
get: (id: number) => http.get<TriggerSummary>(`/triggers/${id}`),
create: (data: Partial<TriggerSummary>) =>
@ -1158,7 +1158,7 @@ export const triggerApi = {
http.put<TriggerSummary>(`/triggers/${id}`, data),
delete: (id: number) => http.delete(`/triggers/${id}`),
ingestEvent: (envelope: {
workspaceId: number
workspaceId: string | number
patternType: string
eventId?: string
senderId?: string

View File

@ -107,7 +107,7 @@ async function handleSubmit() {
}
submitting.value = true
try {
const userId = Number(localStorage.getItem('userId') || '1')
const userId = localStorage.getItem('userId') || '1'
await authApi.changePassword(userId, form.oldPassword, form.newPassword)
mcToast.success(t('auth.passwordChanged'))
close()

View File

@ -397,7 +397,7 @@ function hasUnread(conv: Conversation): boolean {
if (!Number.isFinite(lastActive)) return false
let viewed = 0
try {
viewed = Number(localStorage.getItem(VIEWED_KEY_PREFIX + conv.conversationId) || '0')
viewed = Number(localStorage.getItem(VIEWED_KEY_PREFIX + conv.conversationId) || '0') // snowflake-precision-ok: stored value is a last-viewed epoch-ms timestamp, not an id
} catch {
// Treat as never-viewed when storage is unavailable.
}

View File

@ -127,7 +127,7 @@ onMounted(() => {
store.fetchWorkspaces()
})
function onSelect(id: number) {
function onSelect(id: string) {
open.value = false
if (id !== currentWorkspaceId.value) {
store.switchWorkspace(id)

View File

@ -5,12 +5,14 @@ import type { Capability, WorkspaceRole } from '@/composables/capabilities'
import { ROLE_LEVEL } from '@/composables/capabilities'
export interface Workspace {
id: number
// Backend-issued Snowflake id — kept as a string for its whole lifecycle so a
// Number() round-trip never truncates the 19-digit value (see CLAUDE.md).
id: string
name: string
slug: string
description?: string
basePath?: string
ownerId?: number
ownerId?: string
settingsJson?: string
createTime?: string
updateTime?: string
@ -24,8 +26,11 @@ export interface Workspace {
export const useWorkspaceStore = defineStore('workspace', () => {
const workspaces = ref<Workspace[]>([])
const currentWorkspaceId = ref<number | null>(
Number(localStorage.getItem('mc-workspace-id')) || null
// Stored as a string: the workspace id is a 19-digit Snowflake, so a Number()
// coercion here would corrupt every non-default workspace id and the reloaded
// value would match no workspace, silently snapping back to Default.
const currentWorkspaceId = ref<string | null>(
localStorage.getItem('mc-workspace-id') || null
)
const loading = ref(false)
@ -102,9 +107,9 @@ export const useWorkspaceStore = defineStore('workspace', () => {
}
}
async function switchWorkspace(id: number) {
async function switchWorkspace(id: string) {
currentWorkspaceId.value = id
localStorage.setItem('mc-workspace-id', String(id))
localStorage.setItem('mc-workspace-id', id)
accessLoaded.value = false
currentCapabilities.value = new Set()
await refreshAccess()