Skip to content

feat: Add Amazon S3 connector and UI#1080

Merged
edwinjosechittilappilly merged 1 commit into
IBM_COS_S3_SPIKEfrom
feat-s3
Mar 9, 2026
Merged

feat: Add Amazon S3 connector and UI#1080
edwinjosechittilappilly merged 1 commit into
IBM_COS_S3_SPIKEfrom
feat-s3

Conversation

@edwinjosechittilappilly

Copy link
Copy Markdown
Collaborator

This pull request introduces full Amazon S3 connector support to the frontend, including configuration, bucket selection, and status querying, similar to the existing IBM COS integration. It adds new React Query hooks, S3-specific settings dialogs and forms, and ensures S3 is handled throughout the app wherever connectors are managed or displayed.

Amazon S3 Integration

  • Added new React Query hooks for S3:
    • useS3ConfigureMutation for configuring S3 connections (frontend/app/api/mutations/useS3ConfigureMutation.ts)
    • useS3DefaultsQuery for fetching S3 configuration defaults (frontend/app/api/queries/useS3DefaultsQuery.ts)
    • useS3BucketStatusQuery for retrieving bucket ingestion status (frontend/app/api/queries/useS3BucketStatusQuery.ts)
  • Added S3 settings dialog and form components for secure credential entry, endpoint/region configuration, and interactive bucket selection (frontend/app/settings/_components/s3-settings-dialog.tsx, frontend/app/settings/_components/s3-settings-form.tsx) [1] [2]
  • Updated connector cards to support opening the S3 settings dialog and displaying the AWS logo (frontend/app/settings/_components/connector-cards.tsx) [1] [2] [3] [4]

UI/UX Enhancements

  • Added AWS S3 logo to icon sets and ensured it appears in knowledge sources and connector cards (frontend/app/knowledge/page.tsx, frontend/app/settings/_components/connector-cards.tsx) [1] [2] [3]
  • S3 settings dialog provides real-time feedback for connection testing, error handling, and bucket selection [1] [2]

Connector Handling and Upload Flow

These changes collectively enable users to securely configure, test, and manage Amazon S3 connectors within the app, with a user experience and code structure consistent with other supported cloud providers.

Introduce a full Amazon S3 / S3-compatible connector and integrate it into the app. Backend: add new S3 connector implementation and auth helpers (src/connectors/aws_s3), register API routes for defaults/configure/list/bucket-status, wire S3 into connection manager and connector registry, and include AWS S3 in sync_all. Frontend: add S3 settings form/dialog, React Query hooks (defaults, configure, bucket status), connect S3 UI into connector cards, cloud picker, and upload flow with an S3 bucket view and direct-sync support. CLI/TUI: add S3-related env fields and config prompts. Misc: small UI icon usages and query invalidation added to keep state in sync.
Copilot AI review requested due to automatic review settings March 9, 2026 19:16
@github-actions github-actions Bot added frontend 🟨 Issues related to the UI/UX backend 🔷 Issues related to backend services (OpenSearch, Langflow, APIs) enhancement 🔵 New feature or request labels Mar 9, 2026
@edwinjosechittilappilly edwinjosechittilappilly merged commit aacebb9 into IBM_COS_S3_SPIKE Mar 9, 2026
10 checks passed
@github-actions github-actions Bot deleted the feat-s3 branch March 9, 2026 19:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds full Amazon S3 (and S3-compatible storage) connector support to OpenRAG, closely following the established IBM COS connector pattern. It includes a Python backend connector, REST API endpoints, TUI configuration fields, frontend settings dialogs, React Query hooks, and bucket status/sync views.

Changes:

  • New src/connectors/aws_s3 package with S3Connector, HMAC-based authentication via boto3, and helper functions for credential resolution with env-var fallback.
  • Four new API endpoints (/connectors/aws_s3/defaults, /configure, /{connection_id}/buckets, /{connection_id}/bucket-status) plus registration in src/main.py and the connection manager.
  • Frontend S3 settings dialog, bucket status query hooks, bucket sync view in the upload page, and AWS logo integration in connector cards and knowledge page.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/connectors/aws_s3/__init__.py Module init exporting S3Connector
src/connectors/aws_s3/auth.py Credential resolution and boto3 client/resource factory
src/connectors/aws_s3/connector.py S3 connector implementing BaseConnector (list files, download, ACL)
src/connectors/__init__.py Adds S3Connector to package exports
src/connectors/connection_manager.py Registers aws_s3 connector type in factory and availability check
src/api/connectors.py S3 API endpoints (defaults, configure, list buckets, bucket status) and adds aws_s3 to sync_all_connectors
src/main.py Registers the four S3 API routes
src/tui/managers/env_manager.py Adds aws_s3_endpoint and aws_region config fields and env-var loading
src/tui/config_fields.py Adds S3 Endpoint URL and AWS Region TUI config fields
frontend/app/api/mutations/useS3ConfigureMutation.ts React Query mutation for S3 configure endpoint
frontend/app/api/queries/useS3DefaultsQuery.ts React Query hook for S3 defaults
frontend/app/api/queries/useS3BucketStatusQuery.ts React Query hook for S3 bucket status
frontend/app/settings/_components/s3-settings-dialog.tsx S3 configuration dialog with test/save flow
frontend/app/settings/_components/s3-settings-form.tsx S3 credential/endpoint form with bucket selector
frontend/app/settings/_components/connector-cards.tsx Adds S3 dialog and icon mapping
frontend/app/knowledge/page.tsx Adds AWS logo for S3 knowledge sources
frontend/app/upload/[provider]/page.tsx Adds S3BucketView and S3 to direct-sync providers
frontend/components/cloud-picker/file-item.tsx Adds AWS icon for aws_s3 provider

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +60 to +61
aws_s3_endpoint: str = ""
aws_region: str = ""

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new environment variables AWS_S3_ENDPOINT and AWS_REGION are added to EnvConfig (line 60-61) and the load mapping (line 205-206), but they are missing from the optional_vars list in the save_env method (around line 535-545). This means these values will be loaded from an existing .env file but will be silently dropped when the env file is re-saved through the TUI.

Add the two new entries to the optional_vars list in the save_env method, e.g. after the AWS_SECRET_ACCESS_KEY entry:
("AWS_S3_ENDPOINT", self.config.aws_s3_endpoint) and ("AWS_REGION", self.config.aws_region).

Copilot uses AI. Check for mistakes.
"""Amazon S3 / S3-compatible storage connector for OpenRAG."""

import mimetypes
import os

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The os module is imported but never used in this file. The S3 connector delegates all credential resolution to auth.py, so this import can be removed.

Copilot uses AI. Check for mistakes.
Comment on lines +200 to +364
function S3BucketView({
connector,
syncMutation,
addTask,
onBack,
onDone,
}: {
connector: any;
syncMutation: ReturnType<typeof useSyncConnector>;
addTask: (id: string) => void;
onBack: () => void;
onDone: () => void;
}) {
const queryClient = useQueryClient();
const { data: buckets, isLoading, refetch } = useS3BucketStatusQuery(
connector.connectionId,
{ enabled: true },
);

const [syncingBucket, setSyncingBucket] = useState<string | null>(null);

const invalidateBucketStatus = () => {
queryClient.invalidateQueries({ queryKey: ["s3-bucket-status", connector.connectionId] });
};

const syncAll = () => {
syncMutation.mutate(
{
connectorType: connector.type,
body: {
connection_id: connector.connectionId!,
selected_files: [],
sync_all: true,
},
},
{
onSuccess: (result) => {
invalidateBucketStatus();
if (result.task_ids?.length) {
addTask(result.task_ids[0]);
onDone();
} else {
toast.info("No files found in any bucket.");
}
},
onError: (err) => {
toast.error(err instanceof Error ? err.message : "Sync failed");
},
},
);
};

const syncBucket = (bucketName: string) => {
setSyncingBucket(bucketName);
syncMutation.mutate(
{
connectorType: connector.type,
body: {
connection_id: connector.connectionId!,
selected_files: [],
bucket_filter: [bucketName],
},
},
{
onSuccess: (result) => {
setSyncingBucket(null);
invalidateBucketStatus();
if (result.task_ids?.length) {
addTask(result.task_ids[0]);
onDone();
} else {
toast.info(`No files found in bucket "${bucketName}".`);
}
},
onError: (err) => {
setSyncingBucket(null);
toast.error(err instanceof Error ? err.message : "Sync failed");
},
},
);
};

return (
<>
<div className="mb-8 flex gap-2 items-center">
<Button variant="ghost" onClick={onBack} size="icon">
<ArrowLeft size={18} />
</Button>
<h2 className="text-xl text-[18px] font-semibold">
Add from {connector.name}
</h2>
</div>

<div className="max-w-3xl mx-auto space-y-4">
<div className="flex items-center justify-between">
<p className="text-sm text-muted-foreground">
Select a bucket to ingest, or sync everything at once.
</p>
<div className="flex gap-2">
<Button
variant="ghost"
size="icon"
onClick={() => refetch()}
disabled={isLoading}
title="Refresh bucket status"
>
<RefreshCw size={16} className={isLoading ? "animate-spin" : ""} />
</Button>
<Button
className="bg-foreground text-background hover:bg-foreground/90 font-semibold"
onClick={syncAll}
disabled={syncMutation.isPending}
>
{syncMutation.isPending && !syncingBucket
? "Ingesting…"
: "Sync All Buckets"}
</Button>
</div>
</div>

{isLoading ? (
<div className="flex justify-center py-8">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary" />
</div>
) : !buckets?.length ? (
<div className="rounded-lg border p-6 text-center text-muted-foreground text-sm">
No buckets found. Check your S3 credentials and endpoint.
</div>
) : (
<div className="rounded-lg border divide-y">
{buckets.map((bucket) => (
<div
key={bucket.name}
className="flex items-center justify-between px-4 py-3"
>
<div className="flex items-center gap-3">
<div>
<p className="font-medium text-sm">{bucket.name}</p>
{bucket.ingested_count > 0 && (
<p className="text-xs text-muted-foreground">
{bucket.ingested_count} document{bucket.ingested_count !== 1 ? "s" : ""} ingested
</p>
)}
</div>
</div>
<Button
variant="outline"
size="sm"
onClick={() => syncBucket(bucket.name)}
disabled={syncMutation.isPending}
>
{syncingBucket === bucket.name
? "Ingesting…"
: bucket.ingested_count > 0
? "Re-sync"
: "Ingest"}
</Button>
</div>
))}
</div>
)}
</div>
</>
);
}

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

S3BucketView is nearly identical to IBMCOSBucketView above (same props, same UI, same sync logic). The only differences are the status query hook (useS3BucketStatusQuery vs useIBMCOSBucketStatusQuery) and the query key for invalidation. Consider extracting a shared BucketSyncView component parameterized by the status query hook and query key to avoid maintaining two copies of the same ~160-line component.

Copilot uses AI. Check for mistakes.
@edwinjosechittilappilly edwinjosechittilappilly restored the feat-s3 branch March 9, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend 🔷 Issues related to backend services (OpenSearch, Langflow, APIs) enhancement 🔵 New feature or request frontend 🟨 Issues related to the UI/UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants