feat(rename): complete searchSpace to workspace transition across frontend and backend

- Introduced a comprehensive specification for renaming `searchSpace` to `workspace` in `surfsense_web` and `surfsense_desktop`, ensuring all TypeScript identifiers, React props, and local data structures are updated.
- Implemented migration shims for persisted local state to prevent data loss during the transition.
- Updated observability metrics and IPC channels to reflect the new naming convention.
- Removed legacy `active-search-space` module and replaced it with `active-workspace` to maintain consistency.
- Ensured no behavioral changes or data loss for users during the renaming process.
This commit is contained in:
Anish Sarkar 2026-07-06 15:12:40 +05:30
parent 2a020629c5
commit a8c1fb660d
259 changed files with 5480 additions and 2285 deletions

View file

@ -491,7 +491,7 @@ export const AssistantMessage: FC = () => {
const commentPanelRef = useRef<HTMLDivElement>(null);
const commentTriggerRef = useRef<HTMLButtonElement>(null);
const messageId = useAuiState(({ message }) => message?.id);
const searchSpaceId = useAtomValue(activeWorkspaceIdAtom);
const workspaceId = useAtomValue(activeWorkspaceIdAtom);
const dbMessageId = parseMessageId(messageId);
const commentsEnabled = useAtomValue(commentsEnabledAtom);
@ -520,7 +520,7 @@ export const AssistantMessage: FC = () => {
const commentCount = commentsData?.total_count ?? 0;
const hasComments = commentCount > 0;
const showCommentTrigger = searchSpaceId && commentsEnabled && !isMessageStreaming && dbMessageId;
const showCommentTrigger = workspaceId && commentsEnabled && !isMessageStreaming && dbMessageId;
// Close floating panel when clicking outside (but not on portaled popover/dropdown content)
useEffect(() => {

View file

@ -36,10 +36,10 @@ interface ConnectorIndicatorProps {
export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, ConnectorIndicatorProps>(
(_props, ref) => {
const searchSpaceId = useAtomValue(activeWorkspaceIdAtom);
const workspaceId = useAtomValue(activeWorkspaceIdAtom);
// Real-time document type counts via Zero (updates instantly as docs are indexed)
const documentTypeCounts = useZeroDocumentTypeCounts(searchSpaceId);
const documentTypeCounts = useZeroDocumentTypeCounts(workspaceId);
// Read status inbox items from shared atom (populated by LayoutDataProvider)
// instead of creating a duplicate useInbox("status") hook.
const statusInboxItems = useAtomValue(statusInboxItemsAtom);
@ -124,7 +124,7 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
loading: connectorsLoading,
error: connectorsError,
refreshConnectors: refreshConnectorsSync,
} = useConnectorsSync(searchSpaceId);
} = useConnectorsSync(workspaceId);
const useSyncData = connectorsFromSync.length > 0 || (connectorsLoading && !connectorsError);
const connectors = useSyncData ? connectorsFromSync : allConnectors || [];
@ -142,7 +142,7 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
inboxItems
);
// Get document types that have documents in the search space
// Get document types that have documents in the workspace
const activeDocumentTypes = documentTypeCounts
? Object.entries(documentTypeCounts).filter(([, count]) => count > 0)
: [];
@ -163,7 +163,7 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
open: () => handleOpenChange(true),
}));
if (!searchSpaceId) return null;
if (!workspaceId) return null;
return (
<Dialog open={isOpen} modal={false} onOpenChange={handleOpenChange}>
@ -191,8 +191,8 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
>
<DialogTitle className="sr-only">Manage Connectors</DialogTitle>
{/* YouTube Crawler View - shown when adding YouTube videos */}
{isYouTubeView && searchSpaceId ? (
<YouTubeCrawlerView searchSpaceId={searchSpaceId} onBack={handleBackFromYouTube} />
{isYouTubeView && workspaceId ? (
<YouTubeCrawlerView workspaceId={workspaceId} onBack={handleBackFromYouTube} />
) : viewingMCPList ? (
<ConnectorAccountsListView
connectorType="MCP_CONNECTOR"
@ -253,7 +253,7 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
isSaving={isSaving}
isDisconnecting={isDisconnecting}
isIndexing={indexingConnectorIds.has(editingConnector.id)}
searchSpaceId={searchSpaceId?.toString()}
workspaceId={workspaceId?.toString()}
onStartDateChange={setStartDate}
onEndDateChange={setEndDate}
onPeriodicEnabledChange={setPeriodicEnabled}
@ -346,7 +346,7 @@ export const ConnectorIndicator = forwardRef<ConnectorIndicatorHandle, Connector
<TabsContent value="all" className="m-0">
<AllConnectorsTab
searchQuery={searchQuery}
searchSpaceId={searchSpaceId}
workspaceId={workspaceId}
connectedTypes={connectedTypes}
connectingId={connectingId}
allConnectors={connectors}

View file

@ -159,17 +159,17 @@ export const ObsidianConnectForm: FC<ConnectFormProps> = ({ onBack }) => {
<div className="h-px bg-border/60" />
{/* Step 4 — Pick search space */}
{/* Step 4 — Pick workspace */}
<article>
<header className="mb-3 flex items-center gap-2">
<div className="flex size-7 items-center justify-center rounded-md border border-slate-400/30 text-xs font-medium">
4
</div>
<h3 className="text-sm font-medium sm:text-base">Pick this search space</h3>
<h3 className="text-sm font-medium sm:text-base">Pick this workspace</h3>
</header>
<p className="text-[11px] text-muted-foreground sm:text-xs">
In the plugin's <span className="font-medium">Search space</span> setting, choose the
search space you want this vault to sync into. The connector will appear here
workspace you want this vault to sync into. The connector will appear here
automatically once the plugin makes its first sync.
</p>
</article>

View file

@ -7,7 +7,7 @@ export function getConnectorBenefits(connectorType: string): string[] | null {
LINEAR_CONNECTOR: [
"Search through all your Linear issues and comments",
"Access issue titles, descriptions, and full discussion threads",
"Connect your team's project management directly to your search space",
"Connect your team's project management directly to your workspace",
"Keep your search results up-to-date with latest Linear content",
"Index your Linear issues for enhanced search capabilities",
],
@ -36,63 +36,63 @@ export function getConnectorBenefits(connectorType: string): string[] | null {
SLACK_CONNECTOR: [
"Search through all your Slack messages and conversations",
"Access messages from public and private channels",
"Connect your team's communications directly to your search space",
"Connect your team's communications directly to your workspace",
"Keep your search results up-to-date with latest Slack content",
"Index your Slack conversations for enhanced search capabilities",
],
DISCORD_CONNECTOR: [
"Search through all your Discord messages and conversations",
"Access messages from all accessible channels",
"Connect your community's communications directly to your search space",
"Connect your community's communications directly to your workspace",
"Keep your search results up-to-date with latest Discord content",
"Index your Discord conversations for enhanced search capabilities",
],
NOTION_CONNECTOR: [
"Search through all your Notion pages and databases",
"Access page content, properties, and metadata",
"Connect your knowledge base directly to your search space",
"Connect your knowledge base directly to your workspace",
"Keep your search results up-to-date with latest Notion content",
"Index your Notion workspace for enhanced search capabilities",
],
CONFLUENCE_CONNECTOR: [
"Search through all your Confluence pages and spaces",
"Access page content, comments, and attachments",
"Connect your team's documentation directly to your search space",
"Connect your team's documentation directly to your workspace",
"Keep your search results up-to-date with latest Confluence content",
"Index your Confluence workspace for enhanced search capabilities",
],
BOOKSTACK_CONNECTOR: [
"Search through all your BookStack pages and books",
"Access page content, chapters, and documentation",
"Connect your documentation directly to your search space",
"Connect your documentation directly to your workspace",
"Keep your search results up-to-date with latest BookStack content",
"Index your BookStack instance for enhanced search capabilities",
],
GITHUB_CONNECTOR: [
"Search through code, issues, and documentation from GitHub repositories",
"Access repository content, pull requests, and discussions",
"Connect your codebase directly to your search space",
"Connect your codebase directly to your workspace",
"Keep your search results up-to-date with latest GitHub content",
"Index your GitHub repositories for enhanced search capabilities",
],
JIRA_CONNECTOR: [
"Search through all your Jira issues and tickets",
"Access issue descriptions, comments, and project data",
"Connect your project management directly to your search space",
"Connect your project management directly to your workspace",
"Keep your search results up-to-date with latest Jira content",
"Index your Jira projects for enhanced search capabilities",
],
CLICKUP_CONNECTOR: [
"Search through all your ClickUp tasks and projects",
"Access task descriptions, comments, and project data",
"Connect your task management directly to your search space",
"Connect your task management directly to your workspace",
"Keep your search results up-to-date with latest ClickUp content",
"Index your ClickUp workspace for enhanced search capabilities",
],
LUMA_CONNECTOR: [
"Search through all your Luma events",
"Access event details, descriptions, and attendee information",
"Connect your events directly to your search space",
"Connect your events directly to your workspace",
"Keep your search results up-to-date with latest Luma content",
"Index your Luma events for enhanced search capabilities",
],

View file

@ -165,7 +165,7 @@ export const CirclebackConfig: FC<CirclebackConfigProps> = ({ connector, onNameC
<AlertDescription>
Configure this URL in Circleback Settings Automations Create automation Send
webhook request. The webhook will automatically send meeting notes, transcripts, and
action items to this search space.
action items to this workspace.
</AlertDescription>
</Alert>
)}

View file

@ -8,7 +8,7 @@ export interface ConnectorConfigProps {
connector: SearchSourceConnector;
onConfigChange?: (config: Record<string, unknown>) => void;
onNameChange?: (name: string) => void;
searchSpaceId?: string;
workspaceId?: string;
}
export type ConnectorConfigComponent = FC<ConnectorConfigProps>;

View file

@ -41,7 +41,7 @@ interface ConnectorEditViewProps {
isSaving: boolean;
isDisconnecting: boolean;
isIndexing?: boolean;
searchSpaceId?: string;
workspaceId?: string;
onStartDateChange: (date: Date | undefined) => void;
onEndDateChange: (date: Date | undefined) => void;
onPeriodicEnabledChange: (enabled: boolean) => void;
@ -65,7 +65,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
isSaving,
isDisconnecting,
isIndexing = false,
searchSpaceId,
workspaceId,
onStartDateChange,
onEndDateChange,
onPeriodicEnabledChange,
@ -78,7 +78,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
onConfigChange,
onNameChange,
}) => {
const searchSpaceIdAtom = useAtomValue(activeWorkspaceIdAtom);
const workspaceIdAtom = useAtomValue(activeWorkspaceIdAtom);
const isAuthExpired = connector.config?.auth_expired === true;
const reauthEndpoint = getReauthEndpoint(connector);
const [reauthing, setReauthing] = useState(false);
@ -91,7 +91,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
(connector.is_indexable || connector.connector_type === EnumConnectorName.OBSIDIAN_CONNECTOR);
const handleReauth = useCallback(async () => {
const spaceId = searchSpaceId ?? searchSpaceIdAtom;
const spaceId = workspaceId ?? workspaceIdAtom;
if (!spaceId || !reauthEndpoint) return;
setReauthing(true);
try {
@ -119,7 +119,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
} finally {
setReauthing(false);
}
}, [searchSpaceId, searchSpaceIdAtom, reauthEndpoint, connector.id]);
}, [workspaceId, workspaceIdAtom, reauthEndpoint, connector.id]);
// Get connector-specific config component (MCP-backed connectors use a generic view)
const ConnectorConfigComponent = useMemo(() => {
@ -273,7 +273,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
connector={connector}
onConfigChange={onConfigChange}
onNameChange={onNameChange}
searchSpaceId={searchSpaceId}
workspaceId={workspaceId}
/>
)}

View file

@ -58,7 +58,7 @@ function clearOAuthResultCookie(): void {
}
export const useConnectorDialog = () => {
const searchSpaceId = useAtomValue(activeWorkspaceIdAtom);
const workspaceId = useAtomValue(activeWorkspaceIdAtom);
const { data: allConnectors, refetch: refetchAllConnectors } = useAtomValue(connectorsAtom);
const { mutateAsync: indexConnector } = useAtomValue(indexConnectorMutationAtom);
const { mutateAsync: updateConnector } = useAtomValue(updateConnectorMutationAtom);
@ -140,7 +140,7 @@ export const useConnectorDialog = () => {
const handleAutoIndex = useCallback(
async (connector: SearchSourceConnector, connectorTitle: string, connectorType: string) => {
if (!searchSpaceId || isAutoIndexingRef.current) return;
if (!workspaceId || isAutoIndexingRef.current) return;
isAutoIndexingRef.current = true;
const defaults = AUTO_INDEX_DEFAULTS[connectorType];
@ -165,13 +165,13 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: connector.id,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
start_date: format(startDate, "yyyy-MM-dd"),
end_date: format(endDate, "yyyy-MM-dd"),
},
});
trackIndexWithDateRangeStarted(Number(searchSpaceId), connectorType, connector.id, {
trackIndexWithDateRangeStarted(Number(workspaceId), connectorType, connector.id, {
hasStartDate: true,
hasEndDate: true,
});
@ -188,13 +188,13 @@ export const useConnectorDialog = () => {
});
} finally {
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
queryKey: cacheKeys.logs.summary(Number(workspaceId)),
});
await refetchAllConnectors();
isAutoIndexingRef.current = false;
}
},
[searchSpaceId, indexConnector, updateConnector, refetchAllConnectors]
[workspaceId, indexConnector, updateConnector, refetchAllConnectors]
);
// YouTube view state
@ -206,7 +206,7 @@ export const useConnectorDialog = () => {
// Consume OAuth result from cookie (set by /connectors/callback route handler)
useEffect(() => {
const raw = readOAuthResultCookie();
if (!raw || !searchSpaceId) return;
if (!raw || !workspaceId) return;
clearOAuthResultCookie();
const result = parseOAuthCallbackResult(raw);
@ -221,7 +221,7 @@ export const useConnectorDialog = () => {
if (oauthConnector) {
trackConnectorSetupFailure(
Number(searchSpaceId),
Number(workspaceId),
oauthConnector.connectorType,
result.error,
"oauth_callback"
@ -292,7 +292,7 @@ export const useConnectorDialog = () => {
const connectorValidation = searchSourceConnector.safeParse(newConnector);
if (connectorValidation.success) {
trackConnectorConnected(
Number(searchSpaceId),
Number(workspaceId),
oauthConnector.connectorType,
newConnector.id
);
@ -338,20 +338,20 @@ export const useConnectorDialog = () => {
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchSpaceId, handleAutoIndex, refetchAllConnectors, setIsOpen]);
}, [workspaceId, handleAutoIndex, refetchAllConnectors, setIsOpen]);
// Handle OAuth connection
const handleConnectOAuth = useCallback(
async (connector: (typeof OAUTH_CONNECTORS)[number] | (typeof COMPOSIO_CONNECTORS)[number]) => {
if (!searchSpaceId || !connector.authEndpoint) return;
if (!workspaceId || !connector.authEndpoint) return;
// Set connecting state immediately to disable button and show spinner
setConnectingId(connector.id);
trackConnectorSetupStarted(Number(searchSpaceId), connector.connectorType, "oauth_click");
trackConnectorSetupStarted(Number(workspaceId), connector.connectorType, "oauth_click");
try {
const url = buildBackendUrl(connector.authEndpoint, { space_id: searchSpaceId });
const url = buildBackendUrl(connector.authEndpoint, { space_id: workspaceId });
const response = await authenticatedFetch(url, { method: "GET" });
@ -370,7 +370,7 @@ export const useConnectorDialog = () => {
} catch (error) {
console.error(`Error connecting to ${connector.title}:`, error);
trackConnectorSetupFailure(
Number(searchSpaceId),
Number(workspaceId),
connector.connectorType,
error instanceof Error ? error.message : "oauth_initiation_failed",
"oauth_init"
@ -384,22 +384,22 @@ export const useConnectorDialog = () => {
setConnectingId(null);
}
},
[searchSpaceId]
[workspaceId]
);
// Handle creating YouTube crawler (not a connector, shows view in popup)
const handleCreateYouTubeCrawler = useCallback(() => {
if (!searchSpaceId) return;
if (!workspaceId) return;
setIsYouTubeView(true);
}, [searchSpaceId]);
}, [workspaceId]);
// Handle creating webcrawler connector
const handleCreateWebcrawler = useCallback(async () => {
if (!searchSpaceId) return;
if (!workspaceId) return;
setConnectingId("webcrawler-connector");
trackConnectorSetupStarted(
Number(searchSpaceId),
Number(workspaceId),
EnumConnectorName.WEBCRAWLER_CONNECTOR,
"webcrawler_quick_add"
);
@ -418,7 +418,7 @@ export const useConnectorDialog = () => {
enable_vision_llm: false,
},
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
},
});
@ -433,7 +433,7 @@ export const useConnectorDialog = () => {
if (connectorValidation.success) {
// Track webcrawler connector connected
trackConnectorConnected(
Number(searchSpaceId),
Number(workspaceId),
EnumConnectorName.WEBCRAWLER_CONNECTOR,
connector.id
);
@ -453,7 +453,7 @@ export const useConnectorDialog = () => {
} catch (error) {
console.error("Error creating webcrawler connector:", error);
trackConnectorSetupFailure(
Number(searchSpaceId),
Number(workspaceId),
EnumConnectorName.WEBCRAWLER_CONNECTOR,
error instanceof Error ? error.message : "webcrawler_create_failed",
"webcrawler_quick_add"
@ -462,18 +462,18 @@ export const useConnectorDialog = () => {
} finally {
setConnectingId(null);
}
}, [searchSpaceId, createConnector, refetchAllConnectors, setIsOpen]);
}, [workspaceId, createConnector, refetchAllConnectors, setIsOpen]);
// Handle connecting non-OAuth connectors (like Tavily API, Obsidian plugin, etc.)
const handleConnectNonOAuth = useCallback(
(connectorType: string) => {
if (!searchSpaceId) return;
if (!workspaceId) return;
trackConnectorSetupStarted(Number(searchSpaceId), connectorType, "non_oauth_click");
trackConnectorSetupStarted(Number(workspaceId), connectorType, "non_oauth_click");
setConnectingConnectorType(connectorType);
},
[searchSpaceId]
[workspaceId]
);
// Handle submitting connect form
@ -495,7 +495,7 @@ export const useConnectorDialog = () => {
},
onIndexingStart?: (connectorId: number) => void
) => {
if (!searchSpaceId || !connectingConnectorType) {
if (!workspaceId || !connectingConnectorType) {
return;
}
@ -519,7 +519,7 @@ export const useConnectorDialog = () => {
enable_vision_llm: false,
},
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
},
});
// Refetch connectors to get the new one
@ -536,7 +536,7 @@ export const useConnectorDialog = () => {
const currentConnectorType = connectingConnectorType;
// Track connector connected event for non-OAuth connectors
trackConnectorConnected(Number(searchSpaceId), currentConnectorType, connector.id);
trackConnectorConnected(Number(workspaceId), currentConnectorType, connector.id);
// Find connector title from constants
const connectorInfo = OTHER_CONNECTORS.find(
@ -612,7 +612,7 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: connector.id,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
start_date: startDateStr,
end_date: endDateStr,
},
@ -631,7 +631,7 @@ export const useConnectorDialog = () => {
setIndexingConnectorConfig(null);
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
queryKey: cacheKeys.logs.summary(Number(workspaceId)),
});
await refetchAllConnectors();
@ -684,7 +684,7 @@ export const useConnectorDialog = () => {
} catch (error) {
console.error("Error creating connector:", error);
trackConnectorSetupFailure(
Number(searchSpaceId),
Number(workspaceId),
connectingConnectorType ?? formData.connector_type,
error instanceof Error ? error.message : "connector_create_failed",
"non_oauth_form"
@ -698,7 +698,7 @@ export const useConnectorDialog = () => {
},
[
connectingConnectorType,
searchSpaceId,
workspaceId,
createConnector,
refetchAllConnectors,
updateConnector,
@ -724,7 +724,7 @@ export const useConnectorDialog = () => {
// Handle viewing accounts list for OAuth connector type
const handleViewAccountsList = useCallback(
(connectorType: string, _connectorTitle?: string) => {
if (!searchSpaceId) return;
if (!workspaceId) return;
const oauthConnector =
OAUTH_CONNECTORS.find((c) => c.connectorType === connectorType) ||
@ -736,7 +736,7 @@ export const useConnectorDialog = () => {
});
}
},
[searchSpaceId]
[workspaceId]
);
// Handle going back from accounts list view
@ -746,9 +746,9 @@ export const useConnectorDialog = () => {
// Handle viewing MCP list
const handleViewMCPList = useCallback(() => {
if (!searchSpaceId) return;
if (!workspaceId) return;
setViewingMCPList(true);
}, [searchSpaceId]);
}, [workspaceId]);
// Handle going back from MCP list view
const handleBackFromMCPList = useCallback(() => {
@ -765,7 +765,7 @@ export const useConnectorDialog = () => {
// Handle starting indexing
const handleStartIndexing = useCallback(
async (refreshConnectors: () => void) => {
if (!indexingConfig || !searchSpaceId) return;
if (!indexingConfig || !workspaceId) return;
// Validate date range (skip for Google Drive, Composio Drive, OneDrive, Dropbox, and Webcrawler)
if (
@ -847,7 +847,7 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: indexingConfig.connectorId,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
},
body: {
folders: selectedFolders || [],
@ -870,14 +870,14 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: indexingConfig.connectorId,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
},
});
} else {
await indexConnector({
connector_id: indexingConfig.connectorId,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
start_date: startDateStr,
end_date: endDateStr,
},
@ -886,7 +886,7 @@ export const useConnectorDialog = () => {
// Track index with date range started event
trackIndexWithDateRangeStarted(
Number(searchSpaceId),
Number(workspaceId),
indexingConfig.connectorType,
indexingConfig.connectorId,
{
@ -898,7 +898,7 @@ export const useConnectorDialog = () => {
// Track periodic indexing started if enabled
if (periodicEnabled) {
trackPeriodicIndexingStarted(
Number(searchSpaceId),
Number(workspaceId),
indexingConfig.connectorType,
indexingConfig.connectorId,
parseInt(frequencyMinutes, 10)
@ -915,7 +915,7 @@ export const useConnectorDialog = () => {
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
queryKey: cacheKeys.logs.summary(Number(workspaceId)),
});
} catch (error) {
console.error("Error starting indexing:", error);
@ -926,7 +926,7 @@ export const useConnectorDialog = () => {
},
[
indexingConfig,
searchSpaceId,
workspaceId,
startDate,
endDate,
indexConnector,
@ -951,7 +951,7 @@ export const useConnectorDialog = () => {
// Handle starting edit mode
const handleStartEdit = useCallback(
(connector: SearchSourceConnector) => {
if (!searchSpaceId) return;
if (!workspaceId) return;
// For MCP connectors from "All Connectors" tab, show the list view instead of directly editing
// (unless we're already in the MCP list view or on the Active tab where individual MCPs are shown)
@ -986,11 +986,7 @@ export const useConnectorDialog = () => {
// Track index with date range opened event
if (connector.is_indexable) {
trackIndexWithDateRangeOpened(
Number(searchSpaceId),
connector.connector_type,
connector.id
);
trackIndexWithDateRangeOpened(Number(workspaceId), connector.connector_type, connector.id);
}
setEditingConnector(connector);
@ -1001,13 +997,13 @@ export const useConnectorDialog = () => {
setStartDate(undefined);
setEndDate(undefined);
},
[searchSpaceId, viewingAccountsType, viewingMCPList, handleViewMCPList, activeTab]
[workspaceId, viewingAccountsType, viewingMCPList, handleViewMCPList, activeTab]
);
// Handle saving connector changes
const handleSaveConnector = useCallback(
async (refreshConnectors: () => void) => {
if (!editingConnector || !searchSpaceId || isSaving) return;
if (!editingConnector || !workspaceId || isSaving) return;
// Validate date range (skip for Google Drive/OneDrive/Dropbox which uses folder selection, Webcrawler which uses config, and non-indexable connectors)
if (
@ -1114,7 +1110,7 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: editingConnector.id,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
},
body: {
folders: selectedFolders || [],
@ -1134,7 +1130,7 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: editingConnector.id,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
},
});
indexingDescription = "Re-indexing started with updated configuration.";
@ -1143,7 +1139,7 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: editingConnector.id,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
start_date: startDateStr,
end_date: endDateStr,
},
@ -1157,7 +1153,7 @@ export const useConnectorDialog = () => {
(indexingDescription.includes("Re-indexing") || indexingDescription.includes("indexing"))
) {
trackIndexWithDateRangeStarted(
Number(searchSpaceId),
Number(workspaceId),
editingConnector.connector_type,
editingConnector.id,
{
@ -1170,7 +1166,7 @@ export const useConnectorDialog = () => {
// Track periodic indexing if enabled
if (periodicEnabled && editingConnector.is_indexable) {
trackPeriodicIndexingStarted(
Number(searchSpaceId),
Number(workspaceId),
editingConnector.connector_type,
editingConnector.id,
frequency || parseInt(frequencyMinutes, 10)
@ -1190,7 +1186,7 @@ export const useConnectorDialog = () => {
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
queryKey: cacheKeys.logs.summary(Number(workspaceId)),
});
} catch (error) {
console.error("Error saving connector:", error);
@ -1201,7 +1197,7 @@ export const useConnectorDialog = () => {
},
[
editingConnector,
searchSpaceId,
workspaceId,
isSaving,
startDate,
endDate,
@ -1220,7 +1216,7 @@ export const useConnectorDialog = () => {
// Handle disconnecting connector
const handleDisconnectConnector = useCallback(
async (refreshConnectors: () => void) => {
if (!editingConnector || !searchSpaceId) return;
if (!editingConnector || !workspaceId) return;
setIsDisconnecting(true);
try {
@ -1230,7 +1226,7 @@ export const useConnectorDialog = () => {
// Track connector deleted event
trackConnectorDeleted(
Number(searchSpaceId),
Number(workspaceId),
editingConnector.connector_type,
editingConnector.id
);
@ -1255,7 +1251,7 @@ export const useConnectorDialog = () => {
refreshConnectors();
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
queryKey: cacheKeys.logs.summary(Number(workspaceId)),
});
} catch (error) {
console.error("Error disconnecting connector:", error);
@ -1264,7 +1260,7 @@ export const useConnectorDialog = () => {
setIsDisconnecting(false);
}
},
[editingConnector, searchSpaceId, deleteConnector, cameFromMCPList, setIsOpen]
[editingConnector, workspaceId, deleteConnector, cameFromMCPList, setIsOpen]
);
// Handle quick index (index with selected date range, or backend defaults if none selected)
@ -1276,7 +1272,7 @@ export const useConnectorDialog = () => {
startDate?: Date,
endDate?: Date
) => {
if (!searchSpaceId) {
if (!workspaceId) {
if (stopIndexing) {
stopIndexing(connectorId);
}
@ -1285,7 +1281,7 @@ export const useConnectorDialog = () => {
// Track quick index clicked event
if (connectorType) {
trackQuickIndexClicked(Number(searchSpaceId), connectorType, connectorId);
trackQuickIndexClicked(Number(workspaceId), connectorType, connectorId);
}
try {
@ -1296,7 +1292,7 @@ export const useConnectorDialog = () => {
await indexConnector({
connector_id: connectorId,
queryParams: {
workspace_id: searchSpaceId,
workspace_id: workspaceId,
start_date: startDateStr,
end_date: endDateStr,
},
@ -1305,7 +1301,7 @@ export const useConnectorDialog = () => {
// Invalidate queries to refresh data
queryClient.invalidateQueries({
queryKey: cacheKeys.logs.summary(Number(searchSpaceId)),
queryKey: cacheKeys.logs.summary(Number(workspaceId)),
});
// Note: Don't call stopIndexing here - let useIndexingConnectors hook
// detect when last_indexed_at changes via real-time sync
@ -1318,7 +1314,7 @@ export const useConnectorDialog = () => {
}
}
},
[searchSpaceId, indexConnector]
[workspaceId, indexConnector]
);
// Handle going back from edit view
@ -1406,7 +1402,7 @@ export const useConnectorDialog = () => {
periodicEnabled,
frequencyMinutes,
enableVisionLlm,
searchSpaceId,
workspaceId,
allConnectors,
viewingAccountsType,
viewingMCPList,

View file

@ -44,7 +44,7 @@ export function getConnectorDisplayName(fullName: string): string {
interface AllConnectorsTabProps {
searchQuery: string;
searchSpaceId: string;
workspaceId: string;
connectedTypes: Set<string>;
connectingId: string | null;
allConnectors: SearchSourceConnector[] | undefined;

View file

@ -44,7 +44,7 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
isConnecting = false,
addButtonText,
}) => {
const searchSpaceId = useAtomValue(activeWorkspaceIdAtom);
const workspaceId = useAtomValue(activeWorkspaceIdAtom);
const [reauthingId, setReauthingId] = useState<number | null>(null);
const [confirmDisconnectId, setConfirmDisconnectId] = useState<number | null>(null);
const [disconnectingId, setDisconnectingId] = useState<number | null>(null);
@ -58,13 +58,13 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
const handleReauth = useCallback(
async (connector: SearchSourceConnector) => {
const endpoint = getReauthEndpoint(connector);
if (!searchSpaceId || !endpoint) return;
if (!workspaceId || !endpoint) return;
setReauthingId(connector.id);
try {
const response = await authenticatedFetch(
buildBackendUrl(endpoint, {
connector_id: connector.id,
space_id: searchSpaceId,
space_id: workspaceId,
return_url: window.location.pathname,
})
);
@ -86,7 +86,7 @@ export const ConnectorAccountsListView: FC<ConnectorAccountsListViewProps> = ({
setReauthingId(null);
}
},
[searchSpaceId]
[workspaceId]
);
// Filter connectors to only show those of this type

View file

@ -38,11 +38,11 @@ function extractYoutubeUrls(text: string): string[] {
}
interface YouTubeCrawlerViewProps {
searchSpaceId: string;
workspaceId: string;
onBack: () => void;
}
export const YouTubeCrawlerView: FC<YouTubeCrawlerViewProps> = ({ searchSpaceId, onBack }) => {
export const YouTubeCrawlerView: FC<YouTubeCrawlerViewProps> = ({ workspaceId, onBack }) => {
const t = useTranslations("add_youtube");
const [videoTags, setVideoTags] = useState<TagType[]>([]);
const [activeTagIndex, setActiveTagIndex] = useState<number | null>(null);
@ -165,7 +165,7 @@ export const YouTubeCrawlerView: FC<YouTubeCrawlerViewProps> = ({ searchSpaceId,
{
document_type: "YOUTUBE_VIDEO",
content: videoUrls,
workspace_id: parseInt(searchSpaceId, 10),
workspace_id: parseInt(workspaceId, 10),
},
{
onSuccess: () => {

View file

@ -90,9 +90,9 @@ const DocumentUploadPopupContent: FC<{
isOpen: boolean;
onOpenChange: (open: boolean) => void;
}> = ({ isOpen, onOpenChange }) => {
const searchSpaceId = useAtomValue(activeWorkspaceIdAtom);
const workspaceId = useAtomValue(activeWorkspaceIdAtom);
if (!searchSpaceId) return null;
if (!workspaceId) return null;
const handleSuccess = () => {
onOpenChange(false);
@ -112,12 +112,12 @@ const DocumentUploadPopupContent: FC<{
Upload Documents
</DialogTitle>
<DialogDescription className="text-xs sm:text-base text-muted-foreground/80 line-clamp-1">
Upload and sync your documents to your search space
Upload and sync your documents to your workspace
</DialogDescription>
</DialogHeader>
<div className="px-4 sm:px-6 pb-4 sm:pb-6">
<DocumentUploadTab searchSpaceId={searchSpaceId} onSuccess={handleSuccess} />
<DocumentUploadTab workspaceId={workspaceId} onSuccess={handleSuccess} />
</div>
</div>
</DialogContent>

View file

@ -189,7 +189,7 @@ function FilePathLink({ path, className }: { path: string; className?: string })
const openEditorPanel = useSetAtom(openEditorPanelAtom);
const params = useParams();
const electronAPI = useElectronAPI();
const resolvedSearchSpaceId = getWorkspaceIdNumber(params);
const resolvedWorkspaceId = getWorkspaceIdNumber(params);
const { displayName, isFolder } = getVirtualPathDisplay(path);
const icon = isFolder ? <FolderIcon className="size-3.5" /> : <FileIcon className="size-3.5" />;
@ -204,7 +204,7 @@ function FilePathLink({ path, className }: { path: string; className?: string })
if (electronAPI.getAgentFilesystemMounts) {
try {
const mounts = (await electronAPI.getAgentFilesystemMounts(
resolvedSearchSpaceId
resolvedWorkspaceId
)) as AgentFilesystemMount[];
resolvedLocalPath = normalizeLocalVirtualPathForEditor(path, mounts);
} catch {
@ -215,21 +215,21 @@ function FilePathLink({ path, className }: { path: string; className?: string })
kind: "local_file",
localFilePath: resolvedLocalPath,
title: resolvedLocalPath.split("/").pop() || resolvedLocalPath,
searchSpaceId: resolvedSearchSpaceId,
workspaceId: resolvedWorkspaceId,
});
return;
}
if (!resolvedSearchSpaceId || !path.startsWith("/documents/")) return;
if (!resolvedWorkspaceId || !path.startsWith("/documents/")) return;
try {
const doc = await documentsApiService.getDocumentByVirtualPath({
workspace_id: resolvedSearchSpaceId,
workspace_id: resolvedWorkspaceId,
virtual_path: path,
});
openEditorPanel({
kind: "document",
documentId: doc.id,
searchSpaceId: resolvedSearchSpaceId,
workspaceId: resolvedWorkspaceId,
title: doc.title,
});
} catch {
@ -237,7 +237,7 @@ function FilePathLink({ path, className }: { path: string; className?: string })
}
})();
},
[electronAPI, openEditorPanel, path, resolvedSearchSpaceId]
[electronAPI, openEditorPanel, path, resolvedWorkspaceId]
);
// Folders cannot open in the editor panel — keep them as visual chips.

View file

@ -895,7 +895,7 @@ const Composer: FC = () => {
<ComposerSuggestionPopoverContent side="top">
<DocumentMentionPicker
ref={documentPickerRef}
searchSpaceId={workspaceId ?? 0}
workspaceId={workspaceId ?? 0}
enableChatMentions
currentChatId={threadId}
onSelectionChange={handleDocumentsMention}
@ -961,7 +961,7 @@ const Composer: FC = () => {
</div>
<ComposerAction
isBlockedByOtherUser={isBlockedByOtherUser}
searchSpaceId={workspaceId ?? 0}
workspaceId={workspaceId ?? 0}
onChatModelSelected={handleChatModelSelected}
/>
<ConnectorIndicator showTrigger={false} />
@ -982,13 +982,13 @@ const Composer: FC = () => {
interface ComposerActionProps {
isBlockedByOtherUser?: boolean;
searchSpaceId: number;
workspaceId: number;
onChatModelSelected?: () => void;
}
const ComposerAction: FC<ComposerActionProps> = ({
isBlockedByOtherUser = false,
searchSpaceId,
workspaceId,
onChatModelSelected,
}) => {
const mentionedDocuments = useAtomValue(mentionedDocumentsAtom);
@ -1564,7 +1564,7 @@ const ComposerAction: FC<ComposerActionProps> = ({
)}
<div className="ml-auto flex min-w-0 shrink-0 items-center gap-2">
<ChatHeader
searchSpaceId={searchSpaceId}
workspaceId={workspaceId}
className="h-9 max-w-[44vw] px-2 sm:max-w-[220px] sm:px-3"
onChatModelSelected={onChatModelSelected}
/>

View file

@ -76,33 +76,33 @@ const UserTextPart: FC = () => {
const openEditorPanel = useSetAtom(openEditorPanelAtom);
const router = useRouter();
const params = useParams();
const resolvedSearchSpaceId = getWorkspaceIdNumber(params);
const resolvedWorkspaceId = getWorkspaceIdNumber(params);
const handleOpenDoc = useCallback(
(docId: number, title: string) => {
if (!resolvedSearchSpaceId) {
toast.error("Cannot open document outside a search space.");
if (!resolvedWorkspaceId) {
toast.error("Cannot open document outside a workspace.");
return;
}
openEditorPanel({
kind: "document",
documentId: docId,
searchSpaceId: resolvedSearchSpaceId,
workspaceId: resolvedWorkspaceId,
title,
});
},
[openEditorPanel, resolvedSearchSpaceId]
[openEditorPanel, resolvedWorkspaceId]
);
const handleOpenThread = useCallback(
(threadId: number) => {
if (!resolvedSearchSpaceId) {
toast.error("Cannot open chat outside a search space.");
if (!resolvedWorkspaceId) {
toast.error("Cannot open chat outside a workspace.");
return;
}
router.push(`/dashboard/${resolvedSearchSpaceId}/new-chat/${threadId}`);
router.push(`/dashboard/${resolvedWorkspaceId}/new-chat/${threadId}`);
},
[resolvedSearchSpaceId, router]
[resolvedWorkspaceId, router]
);
const segments = parseMentionSegments(text, mentionedDocs);