mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-06-16 21:03:58 +08:00
fix(providers): confirm discarding unsaved edits on category switch
Previously confirmDiscardIfDirty only fired for Sheet-driven close paths (Cancel button, backdrop, escape). Clicking a different provider in the left rail bypassed the prompt and silently dropped the form changes. ProviderSheet now exposes the existing guard via an imperative handle, which the workbench page calls before swapping the active brand.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { usePageTransitionLayer } from '@/components/common/PageTransitionLayer';
|
||||
import { useHeaderRefresh } from '@/hooks/useHeaderRefresh';
|
||||
@@ -15,7 +15,7 @@ import type {
|
||||
OpenAISortBy,
|
||||
SortDir,
|
||||
} from './components/OpenAIBrandToolbar';
|
||||
import { ProviderSheet } from './sheets/ProviderSheet';
|
||||
import { ProviderSheet, type ProviderSheetHandle } from './sheets/ProviderSheet';
|
||||
import { useProviderWorkbench } from './useProviderWorkbench';
|
||||
import type { ProviderBrand, ProviderResource } from './types';
|
||||
import styles from './ProvidersWorkbenchPage.module.scss';
|
||||
@@ -81,6 +81,7 @@ export function ProvidersWorkbenchPage() {
|
||||
mode: 'detail',
|
||||
resource: null,
|
||||
});
|
||||
const sheetRef = useRef<ProviderSheetHandle>(null);
|
||||
|
||||
const connected = connectionStatus === 'connected';
|
||||
const { usageByProvider, refreshRecentRequests } = useProviderRecentRequests({
|
||||
@@ -372,13 +373,19 @@ export function ProvidersWorkbenchPage() {
|
||||
groups={groups}
|
||||
activeBrand={activeGroup.id}
|
||||
onSelect={(brand) => {
|
||||
setActiveBrand(brand);
|
||||
setFilter('');
|
||||
setOpenaiSelectedModels(new Set());
|
||||
// 关闭 Sheet 以避免数据错位
|
||||
if (sheetState.open && sheetState.brand !== brand) {
|
||||
closeSheet();
|
||||
}
|
||||
const isSwitching = sheetState.open && sheetState.brand !== brand;
|
||||
const proceed = isSwitching && sheetRef.current
|
||||
? sheetRef.current.confirmDiscardIfDirty()
|
||||
: Promise.resolve(true);
|
||||
void proceed.then((ok) => {
|
||||
if (!ok) return;
|
||||
setActiveBrand(brand);
|
||||
setFilter('');
|
||||
setOpenaiSelectedModels(new Set());
|
||||
if (isSwitching) {
|
||||
closeSheet();
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<ProviderResourcePanel
|
||||
@@ -399,6 +406,7 @@ export function ProvidersWorkbenchPage() {
|
||||
</div>
|
||||
|
||||
<ProviderSheet
|
||||
ref={sheetRef}
|
||||
state={sheetState}
|
||||
onClose={closeSheet}
|
||||
onSwitchToEdit={() => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useId, useState } from 'react';
|
||||
import { useCallback, useEffect, useId, useImperativeHandle, useState, type Ref } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Sheet } from '@/components/ui/Sheet';
|
||||
import { IconLoader2, IconPencil } from '@/components/ui/icons';
|
||||
@@ -24,6 +24,10 @@ export interface ProviderSheetState {
|
||||
resource: ProviderResource | null;
|
||||
}
|
||||
|
||||
export interface ProviderSheetHandle {
|
||||
confirmDiscardIfDirty: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
interface ProviderSheetProps {
|
||||
state: ProviderSheetState;
|
||||
onClose: () => void;
|
||||
@@ -31,6 +35,7 @@ interface ProviderSheetProps {
|
||||
workbench: UseProviderWorkbenchResult;
|
||||
onCreated: () => void;
|
||||
onUpdated: () => void;
|
||||
ref?: Ref<ProviderSheetHandle>;
|
||||
}
|
||||
|
||||
export function ProviderSheet({
|
||||
@@ -40,6 +45,7 @@ export function ProviderSheet({
|
||||
workbench,
|
||||
onCreated,
|
||||
onUpdated,
|
||||
ref,
|
||||
}: ProviderSheetProps) {
|
||||
const { t } = useTranslation();
|
||||
const { showConfirmation } = useNotificationStore();
|
||||
@@ -79,6 +85,8 @@ export function ProviderSheet({
|
||||
});
|
||||
}, [isDirty, isEditingForm, showConfirmation, submitting, t]);
|
||||
|
||||
useImperativeHandle(ref, () => ({ confirmDiscardIfDirty }), [confirmDiscardIfDirty]);
|
||||
|
||||
const handleCancelClick = useCallback(() => {
|
||||
void confirmDiscardIfDirty().then((ok) => {
|
||||
if (ok) onClose();
|
||||
|
||||
Reference in New Issue
Block a user