fix(workspaces): stop filtering server list by active workspace in assignment dialog

The workspace edit dialog reused useServers(), which always sends the
X-Active-Workspace header, so admins assigning servers to a workspace
only ever saw servers already in the currently active workspace instead
of the full list. apiClient now lets a caller override the header, and
useServers(allWorkspaces) requests '0' (admin "show all") for that dialog.
This commit is contained in:
markmorado
2026-07-23 21:59:02 +05:00
parent ef5b40b2f7
commit 203ae8bdd6
3 changed files with 19 additions and 9 deletions

View File

@@ -134,7 +134,9 @@ function EditWorkspaceDialog({
const [description, setDescription] = useState(initialDescription);
const { data: workspace } = useWorkspace(workspaceId);
const { data: allServers = [] } = useServers();
// allWorkspaces: этот диалог назначает серверы рабочей области, поэтому
// список не должен фильтроваться заголовком активной рабочей области.
const { data: allServers = [] } = useServers({ allWorkspaces: true });
const { data: allUsers = [] } = useUsers();
const updateServers = useUpdateWorkspaceServers();
const updateUsers = useUpdateWorkspaceUsers();

View File

@@ -15,10 +15,14 @@ export const nodeKeys = {
networks: (serverId: number, node: string) => ['node-networks', serverId, node] as const,
};
export function useServers() {
export function useServers(options?: { allWorkspaces?: boolean }) {
const allWorkspaces = options?.allWorkspaces ?? false;
return useQuery({
queryKey: nodeKeys.servers,
queryFn: () => apiClient.get<ProxmoxServer[]>('/proxmox/api/servers'),
queryKey: allWorkspaces ? [...nodeKeys.servers, 'all-workspaces'] : nodeKeys.servers,
// '0' — просьба к бэкенду игнорировать фильтр активной рабочей области
// (актуально для админ-экранов вроде управления рабочими областями,
// где нужен полный список серверов, а не только текущей области).
queryFn: () => apiClient.get<ProxmoxServer[]>('/proxmox/api/servers', allWorkspaces ? { headers: { 'X-Active-Workspace': '0' } } : undefined),
refetchInterval: 30000,
});
}

View File

@@ -114,9 +114,13 @@ class ApiClient {
headers['Authorization'] = `Bearer ${this.token}`;
}
const wsId = getActiveWorkspaceId();
if (wsId) {
headers['X-Active-Workspace'] = String(wsId);
// Явно переданный заголовок (например, '0' — «показать все области») не
// должен перезатираться значением активной рабочей области по умолчанию.
if (!('X-Active-Workspace' in headers)) {
const wsId = getActiveWorkspaceId();
if (wsId) {
headers['X-Active-Workspace'] = String(wsId);
}
}
const res = await fetch(`${API_BASE}${path}`, {
@@ -150,8 +154,8 @@ class ApiClient {
return res.json();
}
get<T>(path: string) {
return this.request<T>(path);
get<T>(path: string, options?: { headers?: Record<string, string> }) {
return this.request<T>(path, options?.headers ? { headers: options.headers } : undefined);
}
post<T>(path: string, body?: unknown) {