fix: Refactor connector dialog state management and improve modal handling

This commit is contained in:
Anish Sarkar 2026-03-11 11:37:50 +05:30
parent eec4db4a3b
commit 70c3f09261
2 changed files with 165 additions and 152 deletions

View file

@ -316,44 +316,46 @@ export const useConnectorDialog = () => {
}
}
}
} else {
setIsOpen(false);
// Clear indexing config when modal is closed
if (indexingConfig) {
setIndexingConfig(null);
setIndexingConnector(null);
setIndexingConnectorConfig(null);
setStartDate(undefined);
setEndDate(undefined);
setPeriodicEnabled(false);
setFrequencyMinutes("1440");
setEnableSummary(false);
setIsScrolled(false);
setSearchQuery("");
}
// Clear editing connector when modal is closed
if (editingConnector) {
setEditingConnector(null);
setConnectorName(null);
setConnectorConfig(null);
setStartDate(undefined);
setEndDate(undefined);
setPeriodicEnabled(false);
setFrequencyMinutes("1440");
setEnableSummary(false);
setIsScrolled(false);
setSearchQuery("");
}
// Clear connecting connector type when modal is closed
if (connectingConnectorType) {
setConnectingConnectorType(null);
}
// Clear viewing accounts type when modal is closed
if (viewingAccountsType) {
setViewingAccountsType(null);
}
// Clear YouTube view when modal is closed (handled by view param check)
} else {
// Do NOT call setIsOpen(false) here. Closing the dialog is handled
// explicitly by handleOpenChange and the individual action handlers.
// Relying on URL params to close the dialog caused a race condition
// where Next.js router updates from tab switches briefly produced
// stale searchParams without the "modal" key, closing the popup.
// Still clean up sub-view state when the modal param is gone
// (e.g. after browser back navigation or explicit handler URL cleanup).
if (indexingConfig) {
setIndexingConfig(null);
setIndexingConnector(null);
setIndexingConnectorConfig(null);
setStartDate(undefined);
setEndDate(undefined);
setPeriodicEnabled(false);
setFrequencyMinutes("1440");
setEnableSummary(false);
setIsScrolled(false);
setSearchQuery("");
}
if (editingConnector) {
setEditingConnector(null);
setConnectorName(null);
setConnectorConfig(null);
setStartDate(undefined);
setEndDate(undefined);
setPeriodicEnabled(false);
setFrequencyMinutes("1440");
setEnableSummary(false);
setIsScrolled(false);
setSearchQuery("");
}
if (connectingConnectorType) {
setConnectingConnectorType(null);
}
if (viewingAccountsType) {
setViewingAccountsType(null);
}
}
} catch (error) {
// Invalid query params - log but don't crash
console.warn("Invalid connector popup query params:", error);
@ -410,17 +412,18 @@ export const useConnectorDialog = () => {
COMPOSIO_CONNECTORS.find((c) => c.id === params.connector)
: null;
if (earlyConnector && AUTO_INDEX_CONNECTOR_TYPES.has(earlyConnector.connectorType)) {
toast.loading(`Setting up ${earlyConnector.title}...`, { id: "auto-index" });
const url = new URL(window.location.href);
url.searchParams.delete("success");
url.searchParams.delete("connector");
url.searchParams.delete("connectorId");
url.searchParams.delete("view");
url.searchParams.delete("modal");
url.searchParams.delete("tab");
router.replace(url.pathname + url.search, { scroll: false });
}
if (earlyConnector && AUTO_INDEX_CONNECTOR_TYPES.has(earlyConnector.connectorType)) {
toast.loading(`Setting up ${earlyConnector.title}...`, { id: "auto-index" });
setIsOpen(false);
const url = new URL(window.location.href);
url.searchParams.delete("success");
url.searchParams.delete("connector");
url.searchParams.delete("connectorId");
url.searchParams.delete("view");
url.searchParams.delete("modal");
url.searchParams.delete("tab");
router.replace(url.pathname + url.search, { scroll: false });
}
refetchAllConnectors().then(async (result) => {
if (!result.data) {
@ -789,20 +792,22 @@ export const useConnectorDialog = () => {
},
});
const successMessage =
currentConnectorType === "MCP_CONNECTOR"
? `${connector.name} added successfully`
: `${connectorTitle} connected and syncing started!`;
toast.success(successMessage);
const successMessage =
currentConnectorType === "MCP_CONNECTOR"
? `${connector.name} added successfully`
: `${connectorTitle} connected and syncing started!`;
toast.success(successMessage);
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorType");
router.replace(url.pathname + url.search, { scroll: false });
// Close dialog and clean up URL
setIsOpen(false);
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorType");
router.replace(url.pathname + url.search, { scroll: false });
// Clear indexing config state since we're not showing the view
// Clear indexing config state since we're not showing the view
setIndexingConfig(null);
setIndexingConnector(null);
setIndexingConnectorConfig(null);
@ -850,23 +855,24 @@ export const useConnectorDialog = () => {
// Refresh connectors list
await refetchAllConnectors();
} else {
// Other non-indexable connectors - just show success message and close
const successMessage =
currentConnectorType === "MCP_CONNECTOR"
? `${connector.name} added successfully`
: `${connectorTitle} connected successfully!`;
toast.success(successMessage);
// Other non-indexable connectors - just show success message and close
const successMessage =
currentConnectorType === "MCP_CONNECTOR"
? `${connector.name} added successfully`
: `${connectorTitle} connected successfully!`;
toast.success(successMessage);
// Refresh connectors list before closing modal
await refetchAllConnectors();
// Refresh connectors list before closing modal
await refetchAllConnectors();
// Close modal and return to main view
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorType");
router.replace(url.pathname + url.search, { scroll: false });
// Close dialog and clean up URL
setIsOpen(false);
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorType");
router.replace(url.pathname + url.search, { scroll: false });
// Clear indexing config state
setIndexingConfig(null);
@ -894,6 +900,7 @@ export const useConnectorDialog = () => {
updateConnector,
indexConnector,
router,
setIsOpen,
]
);
@ -1122,18 +1129,19 @@ export const useConnectorDialog = () => {
);
}
toast.success(`${indexingConfig.connectorTitle} indexing started`);
toast.success(`${indexingConfig.connectorTitle} indexing started`);
// Update URL - the effect will handle closing the modal and clearing state
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("success");
url.searchParams.delete("connector");
url.searchParams.delete("view");
router.replace(url.pathname + url.search, { scroll: false });
// Close dialog and clean up URL
setIsOpen(false);
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("success");
url.searchParams.delete("connector");
url.searchParams.delete("view");
router.replace(url.pathname + url.search, { scroll: false });
refreshConnectors();
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
});
@ -1156,12 +1164,14 @@ export const useConnectorDialog = () => {
enableSummary,
router,
indexingConnectorConfig,
setIsOpen,
]
);
// Handle skipping indexing
const handleSkipIndexing = useCallback(() => {
// Update URL - the effect will handle closing the modal and clearing state
// Close dialog and clean up URL
setIsOpen(false);
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
@ -1169,7 +1179,7 @@ export const useConnectorDialog = () => {
url.searchParams.delete("connector");
url.searchParams.delete("view");
router.replace(url.pathname + url.search, { scroll: false });
}, [router]);
}, [router, setIsOpen]);
// Handle starting edit mode
const handleStartEdit = useCallback(
@ -1411,41 +1421,43 @@ export const useConnectorDialog = () => {
: indexingDescription,
});
// Update URL - the effect will handle closing the modal and clearing state
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorId");
router.replace(url.pathname + url.search, { scroll: false });
// Close dialog and clean up URL
setIsOpen(false);
const url = new URL(window.location.href);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorId");
router.replace(url.pathname + url.search, { scroll: false });
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
});
} catch (error) {
console.error("Error saving connector:", error);
toast.error("Failed to save connector changes");
} finally {
setIsSaving(false);
}
},
[
editingConnector,
searchSpaceId,
isSaving,
startDate,
endDate,
indexConnector,
updateConnector,
periodicEnabled,
frequencyMinutes,
enableSummary,
getFrequencyLabel,
router,
connectorConfig,
connectorName,
]
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
});
} catch (error) {
console.error("Error saving connector:", error);
toast.error("Failed to save connector changes");
} finally {
setIsSaving(false);
}
},
[
editingConnector,
searchSpaceId,
isSaving,
startDate,
endDate,
indexConnector,
updateConnector,
periodicEnabled,
frequencyMinutes,
enableSummary,
getFrequencyLabel,
router,
connectorConfig,
connectorName,
setIsOpen,
]
);
// Handle disconnecting connector
@ -1472,35 +1484,36 @@ export const useConnectorDialog = () => {
: `${editingConnector.name} disconnected successfully`
);
// Update URL - for MCP from list view, go back to list; otherwise close modal
const url = new URL(window.location.href);
if (editingConnector.connector_type === "MCP_CONNECTOR" && cameFromMCPList) {
// Go back to MCP list view only if we came from there
setViewingMCPList(true);
url.searchParams.set("modal", "connectors");
url.searchParams.set("view", "mcp-list");
url.searchParams.delete("connectorId");
} else {
// Close modal for all other cases
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorId");
}
router.replace(url.pathname + url.search, { scroll: false });
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
});
} catch (error) {
console.error("Error disconnecting connector:", error);
toast.error("Failed to disconnect connector");
} finally {
setIsDisconnecting(false);
// Update URL - for MCP from list view, go back to list; otherwise close modal
const url = new URL(window.location.href);
if (editingConnector.connector_type === "MCP_CONNECTOR" && cameFromMCPList) {
// Go back to MCP list view only if we came from there
setViewingMCPList(true);
url.searchParams.set("modal", "connectors");
url.searchParams.set("view", "mcp-list");
url.searchParams.delete("connectorId");
} else {
// Close dialog for all other cases
setIsOpen(false);
url.searchParams.delete("modal");
url.searchParams.delete("tab");
url.searchParams.delete("view");
url.searchParams.delete("connectorId");
}
},
[editingConnector, searchSpaceId, deleteConnector, router, cameFromMCPList]
router.replace(url.pathname + url.search, { scroll: false });
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
});
} catch (error) {
console.error("Error disconnecting connector:", error);
toast.error("Failed to disconnect connector");
} finally {
setIsDisconnecting(false);
}
},
[editingConnector, searchSpaceId, deleteConnector, router, cameFromMCPList, setIsOpen]
);
// Handle quick index (index with selected date range, or backend defaults if none selected)

View file

@ -9,7 +9,7 @@ import {
Laptop,
LogOut,
Moon,
Settings,
UserCog,
Sun,
} from "lucide-react";
import Image from "next/image";
@ -206,7 +206,7 @@ export function SidebarUserProfile({
<DropdownMenuSeparator className="dark:bg-neutral-700" />
<DropdownMenuItem onClick={onUserSettings}>
<Settings className="h-4 w-4" />
<UserCog className="h-4 w-4" />
{t("user_settings")}
</DropdownMenuItem>
@ -351,7 +351,7 @@ export function SidebarUserProfile({
<DropdownMenuSeparator className="dark:bg-neutral-700" />
<DropdownMenuItem onClick={onUserSettings}>
<Settings className="h-4 w-4" />
<UserCog className="h-4 w-4" />
{t("user_settings")}
</DropdownMenuItem>