merge: isolate concurrent OpenCode chat runs
This commit is contained in:
@@ -202,6 +202,7 @@ export function ProvidersSettings() {
|
||||
const [editingProvider, setEditingProvider] = useState<string | null>(null);
|
||||
const [syncingUserModels, setSyncingUserModels] = useState(false);
|
||||
const [autoUserModelSyncAttempted, setAutoUserModelSyncAttempted] = useState(false);
|
||||
const [runtimeRefreshRequired, setRuntimeRefreshRequired] = useState(false);
|
||||
const vendorMap = new Map(vendors.map((vendor) => [vendor.id, vendor]));
|
||||
const existingVendorIds = new Set(accounts.map((account) => account.vendorId));
|
||||
const displayProviders = useMemo(
|
||||
@@ -214,7 +215,10 @@ export function ProvidersSettings() {
|
||||
refreshProviderSnapshot();
|
||||
}, [refreshProviderSnapshot]);
|
||||
|
||||
const handleImportUserModelConfig = useCallback(async (options: { silent?: boolean } = {}) => {
|
||||
const handleImportUserModelConfig = useCallback(async (options: {
|
||||
silent?: boolean;
|
||||
runtimeRefresh: 'apply' | 'defer';
|
||||
}) => {
|
||||
if (!accessToken) {
|
||||
if (!options.silent) {
|
||||
toast.error(t('aiProviders.toast.loginRequiredForSync', 'Sign in before syncing Makelore models.'));
|
||||
@@ -224,7 +228,12 @@ export function ProvidersSettings() {
|
||||
|
||||
setSyncingUserModels(true);
|
||||
try {
|
||||
await importUserModelConfig(accessToken);
|
||||
const result = await importUserModelConfig(accessToken, {
|
||||
runtimeRefresh: options.runtimeRefresh,
|
||||
});
|
||||
setRuntimeRefreshRequired(
|
||||
options.runtimeRefresh === 'defer' && result.runtimeRefreshRequired,
|
||||
);
|
||||
if (!options.silent) {
|
||||
toast.success(t('aiProviders.toast.syncedUserModels', 'Synced Makelore models'));
|
||||
}
|
||||
@@ -244,7 +253,7 @@ export function ProvidersSettings() {
|
||||
return;
|
||||
}
|
||||
setAutoUserModelSyncAttempted(true);
|
||||
void handleImportUserModelConfig({ silent: true });
|
||||
void handleImportUserModelConfig({ silent: true, runtimeRefresh: 'defer' });
|
||||
}, [
|
||||
accessToken,
|
||||
autoUserModelSyncAttempted,
|
||||
@@ -324,7 +333,7 @@ export function ProvidersSettings() {
|
||||
<Button
|
||||
data-testid="providers-sync-user-models-button"
|
||||
variant="outline"
|
||||
onClick={() => void handleImportUserModelConfig()}
|
||||
onClick={() => void handleImportUserModelConfig({ runtimeRefresh: 'apply' })}
|
||||
disabled={!accessToken || syncingUserModels}
|
||||
className="rounded-full px-4 h-9 shadow-none font-medium text-meta"
|
||||
>
|
||||
@@ -333,7 +342,7 @@ export function ProvidersSettings() {
|
||||
) : (
|
||||
<RefreshCw className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
{t('aiProviders.syncUserModels', 'Sync Makelore models')}
|
||||
{t('aiProviders.syncUserModels', 'Sync and apply Makelore models')}
|
||||
</Button>
|
||||
<Button data-testid="providers-add-button" onClick={() => setShowAddDialog(true)} className="rounded-full px-5 h-9 shadow-none font-medium text-meta">
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
@@ -342,6 +351,18 @@ export function ProvidersSettings() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{runtimeRefreshRequired ? (
|
||||
<p
|
||||
data-testid="providers-runtime-refresh-pending"
|
||||
className="rounded-xl border border-brand/20 bg-brand-soft px-4 py-3 text-sm text-foreground"
|
||||
>
|
||||
{t(
|
||||
'aiProviders.runtimeRefreshPending',
|
||||
'The model list is up to date. Use “Sync and apply Makelore models” when you are ready to restart the runtime.',
|
||||
)}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center py-12 text-muted-foreground bg-surface-subtle rounded-3xl border border-transparent border-dashed">
|
||||
<Loader2 className="h-6 w-6 animate-spin" />
|
||||
|
||||
Reference in New Issue
Block a user