Feat/aws dynamodb explorer#31
Conversation
|
Hi @AncientGear |
|
Please take a look at the comments and the extendability of the noSQL db as well as naming and the functionality goes. |
05001b5 to
d711d34
Compare
|
| Filename | Overview |
|---|---|
| packages/api/src/cloud-spi/dynamodbSchema.ts | New DynamoDB schema; the three metadata-only columns (billingMode, itemCount, sizeBytes) will always render blank in the resource table because ResourceTable reads top-level CloudResource fields only. |
| packages/api/src/adapter-aws/AwsDynamoDbAdapter.ts | New adapter follows the established pattern; get() handles ResourceNotFoundException correctly; search filter and schema delegation are correct. |
| packages/api/src/services/dynamodb.ts | Correct pagination loop; Promise.all fan-out is unbounded and rejects entirely on any DescribeTable failure — a potential issue when many tables exist or during table deletion. |
| packages/api/src/routes/clouds.ts | Added 'dynamodb' to isServiceType(); no bespoke route needed — the generic /:cloud/services/:service/resources handler covers it correctly. |
| packages/api/src/cloudProxy.ts | DynamoDB adapter registered with per-account DynamoDBClient; follows the same pattern as all other adapters. |
| packages/api/src/service/CloudProxyService.ts | DynamoDB added to services() list and schema() dispatch; shows 'coming_soon' for Azure/GCP where no adapter is registered. |
| packages/frontend/src/pages/CloudExplorerPage.tsx | Added 'dynamodb' to normalizeService(); no bespoke panel needed — DynamicResourceView handles it generically. |
| packages/frontend/src/features/cloud-console/useCloudConsoleHomeData.ts | DynamoDB card and count wired correctly for AWS; dynamodbResourcesQuery.isLoading used in resourcesLoading without the cloud === 'aws' guard that secretsQuery.isLoading has. |
| packages/frontend/src/components/Layout.tsx | New DatabaseGroupNav collapsible group correctly handles AWS-only DynamoDB link; Azure falls back to a plain Database NavItem; GCP shows a disabled placeholder. |
| packages/frontend/src/features/cloud-console/cloudConsoleHome.utils.ts | activeServicesDetailFor and resourceDetailFor updated to mention DynamoDB; descriptive strings only, no logic impact. |
| packages/api/src/aws.ts | DynamoDBClient added to client registry and buildClients(); awsRegion exported for reuse by the service layer. |
| packages/frontend/src/types/cloud.ts | DYNAMODB added to CLOUD_SERVICE constant and CloudServiceType union; clean, no issues. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as Browser (React :4500)
participant API as Hono API (:4501)
participant CPX as CloudProxyService
participant ADA as AwsDynamoDbAdapter
participant SVC as DynamoDbService
participant DDB as DynamoDB SDK (:4566)
UI->>API: GET /api/clouds/aws/services/dynamodb/resources
API->>CPX: "listResources('aws', 'dynamodb', {search})"
CPX->>ADA: "list({search})"
ADA->>SVC: listTables()
SVC->>DDB: ListTablesCommand (paginated)
DDB-->>SVC: TableNames[]
loop per table name
SVC->>DDB: DescribeTableCommand (concurrent via Promise.all)
DDB-->>SVC: TableDescription
end
SVC-->>ADA: DynamoDbTable[]
ADA->>ADA: tableToResource() + filterBySearch()
ADA-->>CPX: CloudResource[]
CPX-->>API: CloudResource[]
API-->>UI: JSON array
UI->>API: GET /api/clouds/aws/services/dynamodb/schema
API->>CPX: schema('aws', 'dynamodb')
CPX->>ADA: schema()
ADA-->>CPX: ServiceSchema (columns, filters, actions)
CPX-->>API: ServiceSchema
API-->>UI: JSON schema drives DynamicResourceView
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as Browser (React :4500)
participant API as Hono API (:4501)
participant CPX as CloudProxyService
participant ADA as AwsDynamoDbAdapter
participant SVC as DynamoDbService
participant DDB as DynamoDB SDK (:4566)
UI->>API: GET /api/clouds/aws/services/dynamodb/resources
API->>CPX: "listResources('aws', 'dynamodb', {search})"
CPX->>ADA: "list({search})"
ADA->>SVC: listTables()
SVC->>DDB: ListTablesCommand (paginated)
DDB-->>SVC: TableNames[]
loop per table name
SVC->>DDB: DescribeTableCommand (concurrent via Promise.all)
DDB-->>SVC: TableDescription
end
SVC-->>ADA: DynamoDbTable[]
ADA->>ADA: tableToResource() + filterBySearch()
ADA-->>CPX: CloudResource[]
CPX-->>API: CloudResource[]
API-->>UI: JSON array
UI->>API: GET /api/clouds/aws/services/dynamodb/schema
API->>CPX: schema('aws', 'dynamodb')
CPX->>ADA: schema()
ADA-->>CPX: ServiceSchema (columns, filters, actions)
CPX-->>API: ServiceSchema
API-->>UI: JSON schema drives DynamicResourceView
Reviews (1): Last reviewed commit: "test(frontend): add dynamodb source hygi..." | Re-trigger Greptile
| const dynamodbColumns: TableColumnSchema[] = [ | ||
| {name: 'name', label: 'Name'}, | ||
| {name: 'status', label: 'Status'}, | ||
| {name: 'billingMode', label: 'Billing Mode'}, | ||
| {name: 'itemCount', label: 'Item Count'}, | ||
| {name: 'sizeBytes', label: 'Size (Bytes)'}, |
There was a problem hiding this comment.
DynamoDB columns will always render as dashes in the resource table
The three service-specific columns — billingMode, itemCount, and sizeBytes — point to field names that don't exist at the top level of CloudResource. ResourceTable resolves columns via resource[column.name as keyof CloudResource], so any column name that isn't a known top-level property returns undefined, which formatValue renders as '-'. Compare: the EKS schema uses a version column because version is a first-class field on CloudResource, and the Database schema uses engine / instanceClass for the same reason.
The fix is either to promote billingMode, itemCount, and sizeBytes to top-level fields on CloudResource (both backend types.ts and frontend types/resource.ts) and expose them directly from tableToResource, or alternatively to teach ResourceTable to fall back to resource.metadata[column.name] when a column name isn't a recognized top-level key.
| async listTables(): Promise<DynamoDbTable[]> { | ||
| const tableNames: string[] = [] | ||
| let lastEvaluatedTableName: string | undefined | ||
|
|
||
| do { | ||
| const response = await client.send(new ListTablesCommand({ | ||
| ...(lastEvaluatedTableName ? {ExclusiveStartTableName: lastEvaluatedTableName} : {}), | ||
| })) | ||
| tableNames.push(...(response.TableNames ?? [])) | ||
| lastEvaluatedTableName = response.LastEvaluatedTableName | ||
| } while (lastEvaluatedTableName) | ||
|
|
||
| // ListTables only returns table names, so describe each table to populate the CloudResource metadata used by the explorer. | ||
| return Promise.all(tableNames.map((tableName) => this.describeTable(tableName))) |
There was a problem hiding this comment.
Concurrent
DescribeTable fan-out lacks error isolation
Promise.all rejects as soon as any single DescribeTable call throws. If one table transitions to a terminal state between ListTables and DescribeTable (e.g., DELETING finishing just after the list), the entire listing request fails rather than returning partial results. For a local emulator this is rare, but the call fan-out is unbounded: an account with 200 tables fires 200 concurrent DescribeTable requests before any result is returned. Wrapping each call in Promise.allSettled and filtering fulfilled results would make the listing more resilient.
| const resourcesLoading = storageResourcesQuery.isLoading | ||
| || k8sResourcesQuery.isLoading | ||
| || databaseResourcesQuery.isLoading | ||
| || (cloud === 'aws' && secretsQuery.isLoading) | ||
| || dynamodbResourcesQuery.isLoading |
There was a problem hiding this comment.
Inconsistent cloud-guard on
dynamodbResourcesQuery.isLoading
secretsQuery.isLoading is guarded with cloud === 'aws' before being OR-ed into resourcesLoading, but dynamodbResourcesQuery.isLoading is included without a guard. The query is disabled for non-AWS clouds via hasAvailableService, so in React Query v5 isLoading is false for disabled queries and this has no runtime impact — but the asymmetry is surprising to readers and could silently cause resourcesLoading to stay true longer than expected if the React Query version or the enabled logic changes. Adding (cloud === 'aws' && dynamodbResourcesQuery.isLoading) matches the pattern used for secretsQuery.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
This PR adds DynamoDB as a dedicated AWS service in the unified Cloud Explorer flow.
Repository contribution notes
I reviewed
README.mdfirst.The repository does not define a formal PR/contribution template or a
CONTRIBUTING.mdfile. Based on the README and existing git history, this repo currently expects changes to follow these conventions:This change follows those conventions.
Summary
DatabaseandDynamoDB.What changed
Backend
/api/clouds/:cloud/services/dynamodb/resources/api/clouds/:cloud/dynamodb/resourcesFrontend
dynamodbas a first-class cloud service type./cloud-explorer/aws/dynamodb.DatabaseDynamoDBTooling / test setup
.gitignore.Why this approach
The README makes the architecture rule explicit:
Because of that, DynamoDB was added as a separate normalized service instead of being merged into the existing AWS Database/RDS path.
This keeps:
Out of scope
PR: AWS DynamoDB explorer support
This PR adds DynamoDB as a dedicated AWS service in the unified Cloud Explorer flow.
Testing
npm exec --package bun -- bun test packages/api/srcpnpm --filter @floci/frontend testpnpm type-checkReview path
packages/api/src/services/dynamodb.tspackages/api/src/adapter-aws/AwsDynamoDbAdapter.tspackages/api/src/routes/clouds.tspackages/frontend/src/types/cloud.tspackages/frontend/src/pages/CloudExplorerPage.tsxpackages/frontend/src/features/cloud-console/useCloudConsoleHomeData.tspackages/frontend/src/components/Layout.tsxpackages/frontend/src/index.cssCommits included
feat(aws): add dynamodb explorer supporttest(frontend): add dynamodb source hygiene guard