feat: Enhance Slack Connector Functionality

I've implemented several improvements and new features for the Slack connector,
addressing your requirements for more granular control over indexing
and data synchronization.

Key changes include:

Backend (`surfsense_backend`):
- I've updated the `SearchSourceConnector` schema for Slack to include new
  configuration options:
    - `slack_periodic_indexing_enabled` (boolean)
    - `slack_periodic_indexing_frequency` (string: "daily", "weekly", "monthly")
    - `slack_max_messages_per_channel_periodic` (integer)
- I've modified the `index_slack_messages` task:
    - It now supports on-demand re-indexing of specific `target_channel_ids`.
    - It allows `force_reindex_all_messages` to override `last_indexed_at`
      for specified channels, using initial indexing settings or custom
      date ranges (`reindex_start_date_str`, `reindex_latest_date_str`).
    - It uses `slack_max_messages_per_channel_periodic` for regular
      periodic updates.
- I've updated the Slack Connector Routes:
    - The `/slack/{connector_id}/reindex-channels` endpoint now accepts
      `channel_ids`, `force_reindex_all_messages`, `reindex_start_date`,
      and `reindex_latest_date` to trigger targeted re-indexing.
    - The main `/connector/{id}/index` endpoint for Slack can now accept
      `force_full_reindex` to re-index all configured channels from scratch.

Frontend (`surfsense_web`):
- I've created `EditSlackConnectorConfigForm.tsx` to provide a dedicated UI
  for Slack connector settings, including the new periodic indexing fields.
- I've integrated this form into the main connector editing page
  (`.../connectors/[connector_id]/edit/page.tsx`).
- I've enhanced the Slack connector edit page with a "Channel Management" tab:
    - UI for discovering Slack channels via `/api/v1/slack/{id}/discover-channels`.
    - Allows selection of channels to be saved into
      `config.slack_selected_channel_ids` when membership filter is "selected".
    - UI for triggering on-demand re-indexing of selected channels via
      `/api/v1/slack/{id}/reindex-channels`, with options for forcing
      full re-index and specifying date ranges.
- I've updated the `useSearchSourceConnectors.ts` hook:
    - I've added the `discoverSlackChannels` function.
    - I've added the `reindexSlackChannels` function with parameters for
      channel IDs, force flag, and date ranges.

These changes fulfill your requirements for:
1. Configurable Membership/Join Behavior (via existing `slack_membership_filter_type` and new channel selection UI).
2. Configurable Periodic Indexing (new backend schema and UI fields).
3. Granular Channel Selection (new UI for discovering and selecting channels).
4. On-Demand Re-index (new backend and UI capabilities for specific channels).
5. Initial Indexing Timestamp Range (I've verified existing backend logic and UI).
This commit is contained in:
google-labs-jules[bot] 2025-05-28 09:36:25 +00:00
parent d40de3bce2
commit d1f11d4fbb
6 changed files with 1206 additions and 436 deletions

View file

@ -6,11 +6,27 @@ export interface SearchSourceConnector {
connector_type: string;
is_indexable: boolean;
last_indexed_at: string | null;
config: Record<string, any>;
config: Record<string, any>; // This allows any keys, including new Slack fields
user_id?: string;
created_at?: string;
}
// Interface for Slack channel discovery
export interface SlackChannelInfo {
id: string;
name: string;
is_private: boolean;
is_member: boolean;
}
// Interface for re-indexing request payload (though used internally)
interface ReindexSlackChannelsPayload {
channel_ids: string[];
force_reindex_all_messages?: boolean;
reindex_start_date?: string | null; // Allow null to be passed if date is empty
reindex_latest_date?: string | null; // Allow null to be passed if date is empty
}
export interface ConnectorSourceItem {
id: number;
name: string;
@ -300,6 +316,83 @@ export const useSearchSourceConnectors = () => {
return connectorSourceItems;
}, [connectorSourceItems]);
// Helper function for authenticated fetch requests
const fetchWithAuth = async (url: string, options: RequestInit = {}) => {
const token = localStorage.getItem('surfsense_bearer_token');
if (!token) {
throw new Error('No authentication token found');
}
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
...options.headers,
};
const response = await fetch(url, { ...options, headers });
if (!response.ok) {
const errorBody = await response.text(); // Try to get more error info
throw new Error(`API request failed: ${response.statusText} - ${errorBody}`);
}
// For 202 or 204, response.json() will fail. Handle it.
if (response.status === 202 || response.status === 204) {
return null; // Or some specific success indicator
}
return response.json();
};
/**
* Discover Slack channels for a given connector
*/
const discoverSlackChannels = async (connectorId: number): Promise<SlackChannelInfo[]> => {
try {
const data = await fetchWithAuth(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/slack/${connectorId}/discover-channels`,
{ method: 'GET' }
);
// The backend route for discover-channels returns { channels: SlackChannelInfo[] }
// So, we need to access data.channels
return data.channels as SlackChannelInfo[];
} catch (err) {
console.error(`Error discovering Slack channels for connector ${connectorId}:`, err);
throw err; // Re-throw to be handled by the caller
}
};
/**
* Trigger re-indexing for specific Slack channels
*/
const reindexSlackChannels = async (
connectorId: number,
channelIds: string[],
forceReindexAllMessages?: boolean,
reindexStartDate?: string,
reindexLatestDate?: string
): Promise<any> => {
try {
const payload: ReindexSlackChannelsPayload = {
channel_ids: channelIds,
force_reindex_all_messages: forceReindexAllMessages,
reindex_start_date: reindexStartDate || null, // Ensure null if empty string
reindex_latest_date: reindexLatestDate || null, // Ensure null if empty string
};
const result = await fetchWithAuth(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/slack/${connectorId}/reindex-channels`,
{
method: 'POST',
body: JSON.stringify(payload),
}
);
return result; // Typically a success message or status
} catch (err) {
console.error(`Error re-indexing Slack channels for connector ${connectorId}:`, err);
throw err; // Re-throw to be handled by the caller
}
};
return {
connectors,
isLoading,
@ -309,6 +402,8 @@ export const useSearchSourceConnectors = () => {
deleteConnector,
indexConnector,
getConnectorSourceItems,
connectorSourceItems
connectorSourceItems,
discoverSlackChannels, // Export new function
reindexSlackChannels, // Export new function
};
};
};