From f11359345a2475b434a8e1dd3cfa02f2bc9b7e21 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 22 Mar 2024 12:31:49 -0400 Subject: [PATCH] feat(sdk)!: sunset `ex.DynamodbTable` (#6038) The Wing library ecosystem is steadily growing, and we now have a dedicated [winglib](https://github.com/winglang/winglibs) for DynamoDB, which you can use with: ``` bring dynamodb; ``` It supports both the `sim` and `tf-aws` targets, and includes newly added support for DynamoDB streams. To lighten our maintenance load (and build times), this PR removes the built-in `ex.DynamodbTable` class from the core Wing SDK. If you have any troubles with the new dedicated winglib, please let us know by opening an issue or sending a message on the Wing slack - we're happy to help. BREAKING CHANGE: `ex.DynamodbTable` and related types have been removed from the built-in SDK. We recommend using the dedicated [dynamodb winglib](https://www.npmjs.com/package/@winglibs/dynamodb) instead. ## Checklist - [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted) - [x] Description explains motivation and solution - [x] Tests added (always) - [x] Docs updated (only required for features) - [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing *By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*. --- .../app/test/ex.dynamodb-table/index.test.ts | 36 - .../console/app/test/ex.dynamodb-table/main.w | 7 - .../design-system/src/icons/dynamodb-icon.tsx | 43 - .../design-system/src/utils/icon-utils.ts | 4 - .../server/src/router/dynamodb-table.ts | 117 - .../console/server/src/router/index.ts | 2 - .../console/server/src/wingsdk.ts | 7 +- .../dynamodb-table-interaction-view.tsx | 93 - .../features/resource-interaction-view.tsx | 4 - .../ui/src/services/use-dynamodb-table.ts | 48 - .../ui/src/ui/dynamodb-table-interaction.tsx | 330 --- .../04-standard-library/aws/api-reference.md | 86 - .../compatibility/compatibility.json | 36 +- .../ex/dynamodb-table/_category_.yml | 3 - .../ex/dynamodb-table/interfaces.md | 2323 ----------------- .../ex/dynamodb-table/table.md | 700 ----- .../dynamodb-table/aws-dynamodb.test.w | 40 - .../global-secondary-index.test.w | 104 - .../sdk_tests/dynamodb-table/query.test.w | 41 - .../dynamodb-table/transaction.test.w | 63 - libs/awscdk/src/app.ts | 13 +- libs/awscdk/src/dynamodb-table.inflight.ts | 1 - libs/awscdk/src/dynamodb-table.ts | 91 - libs/awscdk/src/index.ts | 4 +- .../__snapshots__/dynamodb-table.test.ts.snap | 255 -- libs/awscdk/test/dynamodb-table.test.ts | 55 - libs/wingsdk/scripts/docgen.mts | 7 +- libs/wingsdk/src/ex/dynamodb-table/index.ts | 2 - .../src/ex/dynamodb-table/interfaces.md | 7 - .../src/ex/dynamodb-table/interfaces.ts | 877 ------- libs/wingsdk/src/ex/dynamodb-table/table.md | 7 - libs/wingsdk/src/ex/dynamodb-table/table.ts | 694 ----- libs/wingsdk/src/ex/index.ts | 1 - .../src/shared-aws/dynamodb-table.inflight.ts | 15 - libs/wingsdk/src/shared-aws/dynamodb-table.ts | 52 - libs/wingsdk/src/shared-aws/index.ts | 1 - libs/wingsdk/src/shared-aws/permissions.ts | 77 - libs/wingsdk/src/target-sim/app.ts | 10 +- .../src/target-sim/dynamodb-table.inflight.ts | 146 -- libs/wingsdk/src/target-sim/dynamodb-table.ts | 86 - .../src/target-sim/schema-resources.ts | 44 +- libs/wingsdk/src/target-tf-aws/app.ts | 6 +- .../src/target-tf-aws/dynamodb-table.ts | 100 - libs/wingsdk/src/target-tf-aws/index.ts | 1 - .../__snapshots__/connections.test.ts.snap | 4 - .../dynamodb-table.inflight.test.ts | 156 -- .../target-sim/__snapshots__/api.test.ts.snap | 64 - .../__snapshots__/bucket.test.ts.snap | 16 - .../__snapshots__/counter.test.ts.snap | 28 - .../__snapshots__/file-counter.test.ts.snap | 4 - .../__snapshots__/function.test.ts.snap | 24 - .../immutable-capture.test.ts.snap | 56 - .../__snapshots__/on-deploy.test.ts.snap | 4 - .../__snapshots__/queue.test.ts.snap | 20 - .../__snapshots__/redis.test.ts.snap | 4 - .../__snapshots__/schedule.test.ts.snap | 16 - .../__snapshots__/secret.test.ts.snap | 4 - .../__snapshots__/service.test.ts.snap | 4 - .../__snapshots__/table.test.ts.snap | 28 - .../__snapshots__/test.test.ts.snap | 4 - .../__snapshots__/topic.test.ts.snap | 4 - .../test/target-sim/dynamodb-table.test.ts | 597 ----- .../__snapshots__/dynamodb-table.test.ts.snap | 350 --- .../test/target-tf-aws/dynamodb-table.test.ts | 111 - .../aws-dynamodb.test.w_compile_tf-aws.md | 47 - .../aws-dynamodb.test.w_test_sim.md | 12 - ...l-secondary-index.test.w_compile_tf-aws.md | 88 - .../global-secondary-index.test.w_test_sim.md | 12 - .../query.test.w_compile_tf-aws.md | 47 - .../dynamodb-table/query.test.w_test_sim.md | 12 - .../transaction.test.w_compile_tf-aws.md | 47 - .../transaction.test.w_test_sim.md | 12 - 72 files changed, 12 insertions(+), 8402 deletions(-) delete mode 100644 apps/wing-console/console/app/test/ex.dynamodb-table/index.test.ts delete mode 100644 apps/wing-console/console/app/test/ex.dynamodb-table/main.w delete mode 100644 apps/wing-console/console/design-system/src/icons/dynamodb-icon.tsx delete mode 100644 apps/wing-console/console/server/src/router/dynamodb-table.ts delete mode 100644 apps/wing-console/console/ui/src/features/dynamodb-table-interaction-view.tsx delete mode 100644 apps/wing-console/console/ui/src/services/use-dynamodb-table.ts delete mode 100644 apps/wing-console/console/ui/src/ui/dynamodb-table-interaction.tsx delete mode 100644 docs/docs/04-standard-library/ex/dynamodb-table/_category_.yml delete mode 100644 docs/docs/04-standard-library/ex/dynamodb-table/interfaces.md delete mode 100644 docs/docs/04-standard-library/ex/dynamodb-table/table.md delete mode 100644 examples/tests/sdk_tests/dynamodb-table/aws-dynamodb.test.w delete mode 100644 examples/tests/sdk_tests/dynamodb-table/global-secondary-index.test.w delete mode 100644 examples/tests/sdk_tests/dynamodb-table/query.test.w delete mode 100644 examples/tests/sdk_tests/dynamodb-table/transaction.test.w delete mode 100644 libs/awscdk/src/dynamodb-table.inflight.ts delete mode 100644 libs/awscdk/src/dynamodb-table.ts delete mode 100644 libs/awscdk/test/__snapshots__/dynamodb-table.test.ts.snap delete mode 100644 libs/awscdk/test/dynamodb-table.test.ts delete mode 100644 libs/wingsdk/src/ex/dynamodb-table/index.ts delete mode 100644 libs/wingsdk/src/ex/dynamodb-table/interfaces.md delete mode 100644 libs/wingsdk/src/ex/dynamodb-table/interfaces.ts delete mode 100644 libs/wingsdk/src/ex/dynamodb-table/table.md delete mode 100644 libs/wingsdk/src/ex/dynamodb-table/table.ts delete mode 100644 libs/wingsdk/src/shared-aws/dynamodb-table.inflight.ts delete mode 100644 libs/wingsdk/src/shared-aws/dynamodb-table.ts delete mode 100644 libs/wingsdk/src/target-sim/dynamodb-table.inflight.ts delete mode 100644 libs/wingsdk/src/target-sim/dynamodb-table.ts delete mode 100644 libs/wingsdk/src/target-tf-aws/dynamodb-table.ts delete mode 100644 libs/wingsdk/test/shared-aws/dynamodb-table.inflight.test.ts delete mode 100644 libs/wingsdk/test/target-sim/dynamodb-table.test.ts delete mode 100644 libs/wingsdk/test/target-tf-aws/__snapshots__/dynamodb-table.test.ts.snap delete mode 100644 libs/wingsdk/test/target-tf-aws/dynamodb-table.test.ts delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/aws-dynamodb.test.w_compile_tf-aws.md delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/aws-dynamodb.test.w_test_sim.md delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/global-secondary-index.test.w_compile_tf-aws.md delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/global-secondary-index.test.w_test_sim.md delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/query.test.w_compile_tf-aws.md delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/query.test.w_test_sim.md delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/transaction.test.w_compile_tf-aws.md delete mode 100644 tools/hangar/__snapshots__/test_corpus/sdk_tests/dynamodb-table/transaction.test.w_test_sim.md diff --git a/apps/wing-console/console/app/test/ex.dynamodb-table/index.test.ts b/apps/wing-console/console/app/test/ex.dynamodb-table/index.test.ts deleted file mode 100644 index 6d935bc2fb0..00000000000 --- a/apps/wing-console/console/app/test/ex.dynamodb-table/index.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { type Page, expect, test } from "@playwright/test"; - -import { describe } from "../describe.js"; -import { getResourceNode } from "../helpers.js"; - -const addRow = async (page: Page, data?: Record) => { - await page.getByTestId("ex.DynamodbTable:new-row").click(); - await page.getByTestId("ex.DynamodbTable:new-row").fill(JSON.stringify(data)); - - const addRowButton = page.getByTestId("ex.DynamodbTable:add-row"); - await addRowButton.click(); - - const row = page.getByTestId("ex.DynamodbTable:row-0"); - await expect(row).toBeVisible(); -}; - -describe(`${__dirname}/main.w`, () => { - test.skip("adds new item", async ({ page }) => { - await getResourceNode(page, "root/Default/DynamodbTable").click(); - - await addRow(page, { id: "1", key1: "value1", key2: "value2" }); - }); - - test.skip("removes row", async ({ page }) => { - await getResourceNode(page, "root/Default/DynamodbTable").click(); - - await addRow(page, { id: "1", key1: "value1", key2: "value2" }); - - const deleteButton = page.getByTestId("ex.DynamodbTable:remove-row-0"); - await expect(deleteButton).toBeEnabled(); - await deleteButton.click(); - - const row = page.getByTestId("ex.DynamodbTable:row-0"); - await expect(row).toBeHidden(); - }); -}); diff --git a/apps/wing-console/console/app/test/ex.dynamodb-table/main.w b/apps/wing-console/console/app/test/ex.dynamodb-table/main.w deleted file mode 100644 index 5c7dc90019e..00000000000 --- a/apps/wing-console/console/app/test/ex.dynamodb-table/main.w +++ /dev/null @@ -1,7 +0,0 @@ -bring ex; - -new ex.DynamodbTable({ - name: "table", - attributeDefinitions: { "id": "S" }, - hashKey: "id" - }); diff --git a/apps/wing-console/console/design-system/src/icons/dynamodb-icon.tsx b/apps/wing-console/console/design-system/src/icons/dynamodb-icon.tsx deleted file mode 100644 index 6ddfe996f8b..00000000000 --- a/apps/wing-console/console/design-system/src/icons/dynamodb-icon.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { forwardRef } from "react"; - -type DynamoDBIconProps = React.PropsWithoutRef< - React.SVGProps -> & { - title?: string; - titleId?: string; -} & React.RefAttributes; - -export const DynamoDBIcon = forwardRef( - ({ title, titleId, ...props }, svgRef) => { - return ( - - ); - }, -); diff --git a/apps/wing-console/console/design-system/src/utils/icon-utils.ts b/apps/wing-console/console/design-system/src/utils/icon-utils.ts index e3f23c8d356..4b77766240a 100644 --- a/apps/wing-console/console/design-system/src/utils/icon-utils.ts +++ b/apps/wing-console/console/design-system/src/utils/icon-utils.ts @@ -26,7 +26,6 @@ import { KeyIcon as SolidKeyIcon, } from "@heroicons/react/24/solid"; -import { DynamoDBIcon } from "../icons/dynamodb-icon.js"; import { ReactIcon } from "../icons/react-icon.js"; import { RedisIcon } from "../icons/redis-icon.js"; @@ -86,9 +85,6 @@ export const getResourceIconComponent = ( case "@winglang/sdk.cloud.Secret": { return solid ? SolidKeyIcon : KeyIcon; } - case "@winglang/sdk.ex.DynamodbTable": { - return DynamoDBIcon; - } default: { return CubeIcon; } diff --git a/apps/wing-console/console/server/src/router/dynamodb-table.ts b/apps/wing-console/console/server/src/router/dynamodb-table.ts deleted file mode 100644 index 238a8db6fb3..00000000000 --- a/apps/wing-console/console/server/src/router/dynamodb-table.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { z } from "zod"; - -import { createProcedure, createRouter } from "../utils/createRouter.js"; -import type { - DynamodbTableSchema, - IDynamodbTableClient, - Json, -} from "../wingsdk.js"; - -export const createDynamodbTableRouter = () => { - return createRouter({ - "dynamodb-table.info": createProcedure - .meta({ - analytics: { - resource: "DynamodbTable", - action: "scan", - }, - }) - .input( - z.object({ - resourcePath: z.string(), - }), - ) - .query(async ({ input, ctx }) => { - const simulator = await ctx.simulator(); - const schema = simulator.getResourceConfig( - input.resourcePath, - ) as DynamodbTableSchema; - const client = simulator.getResource( - input.resourcePath, - ) as IDynamodbTableClient; - const rows = await client.scan(); - const attributeDefinitions = schema.props.attributeDefinitions; - const hashKey = schema.props.hashKey; - const rangeKey = schema.props.rangeKey; - return { - name: schema.props.name, - attributeDefinitions, - hashKey, - rangeKey, - rows, - }; - }), - "dynamodb-table.get": createProcedure - .meta({ - analytics: { - resource: "DynamodbTable", - action: "getItem", - }, - }) - .input( - z.object({ - resourcePath: z.string(), - key: z.record(z.any()), - }), - ) - .query(async ({ input, ctx }) => { - const simulator = await ctx.simulator(); - const client = simulator.getResource( - input.resourcePath, - ) as IDynamodbTableClient; - const { item } = await client.getItem(input.key as any); - return item; - }), - "dynamodb-table.insert": createProcedure - .meta({ - analytics: { - resource: "DynamodbTable", - action: "putItem", - }, - }) - .input( - z.object({ - resourcePath: z.string(), - data: z.record(z.any()), - }), - ) - .mutation(async ({ input, ctx }) => { - const simulator = await ctx.simulator(); - const client = simulator.getResource( - input.resourcePath, - ) as IDynamodbTableClient; - - await client.putItem({ item: input.data as Json }); - }), - "dynamodb-table.delete": createProcedure - .meta({ - analytics: { - resource: "DynamodbTable", - action: "deleteItem", - }, - }) - .input( - z.object({ - resourcePath: z.string(), - data: z.record(z.any()), - }), - ) - .mutation(async ({ input, ctx }) => { - const simulator = await ctx.simulator(); - const client = simulator.getResource( - input.resourcePath, - ) as IDynamodbTableClient; - - const schema = simulator.getResourceConfig( - input.resourcePath, - ) as DynamodbTableSchema; - const itemKey = { - [schema.props.hashKey]: input.data[schema.props.hashKey], - ...(schema.props.rangeKey - ? { [schema.props.rangeKey]: input.data[schema.props.rangeKey] } - : {}), - }; - return await client.deleteItem({ key: itemKey as Json }); - }), - }); -}; diff --git a/apps/wing-console/console/server/src/router/index.ts b/apps/wing-console/console/server/src/router/index.ts index d357e2df155..46a1cddd8cf 100644 --- a/apps/wing-console/console/server/src/router/index.ts +++ b/apps/wing-console/console/server/src/router/index.ts @@ -5,7 +5,6 @@ import { createAppRouter } from "./app.js"; import { createBucketRouter } from "./bucket.js"; import { createConfigRouter } from "./config.js"; import { createCounterRouter } from "./counter.js"; -import { createDynamodbTableRouter } from "./dynamodb-table.js"; import { createEndpointRouter } from "./endpoint.js"; import { createFunctionRouter } from "./function.js"; import { createQueueRouter } from "./queue.js"; @@ -35,7 +34,6 @@ export const mergeAllRouters = () => { createWebsiteRouter(), createReactAppRouter(), createConfigRouter(), - createDynamodbTableRouter(), createEndpointRouter(), ); diff --git a/apps/wing-console/console/server/src/wingsdk.ts b/apps/wing-console/console/server/src/wingsdk.ts index b2e83431f09..55a8577a71e 100644 --- a/apps/wing-console/console/server/src/wingsdk.ts +++ b/apps/wing-console/console/server/src/wingsdk.ts @@ -18,15 +18,10 @@ export type { export type { ITestRunnerClient } from "@winglang/sdk/lib/std/index.js"; -export type { - IRedisClient, - ITableClient, - IDynamodbTableClient, -} from "@winglang/sdk/lib/ex/index.js"; +export type { IRedisClient, ITableClient } from "@winglang/sdk/lib/ex/index.js"; export type { ApiSchema, - DynamodbTableSchema, TableSchema, WebsiteSchema, } from "@winglang/sdk/lib/target-sim/schema-resources.js"; diff --git a/apps/wing-console/console/ui/src/features/dynamodb-table-interaction-view.tsx b/apps/wing-console/console/ui/src/features/dynamodb-table-interaction-view.tsx deleted file mode 100644 index 60df8a3efe8..00000000000 --- a/apps/wing-console/console/ui/src/features/dynamodb-table-interaction-view.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { useNotifications, Attribute } from "@wingconsole/design-system"; -import { memo, useCallback, useEffect, useState } from "react"; - -import { useDynamodbTable } from "../services/use-dynamodb-table.js"; -import type { RawRow } from "../ui/dynamodb-table-interaction.js"; -import { DynamodbTableInteraction } from "../ui/dynamodb-table-interaction.js"; - -export interface DynamodbTableInteractionViewProps { - resourcePath: string; -} - -export const DynamodbTableInteractionView = memo( - ({ resourcePath }: DynamodbTableInteractionViewProps) => { - const notifications = useNotifications(); - - const showError = useCallback( - (error: string) => { - notifications.showNotification("Error", { - body: error, - type: "error", - }); - }, - [notifications], - ); - - const { table, removeRow, addRow, loading } = useDynamodbTable({ - resourcePath, - }); - - const [rows, setRows] = useState<{ data: {}; error: string }[]>([]); - - const onAddRow = useCallback( - async (data: RawRow) => { - try { - if (data.error) { - showError(`Row error: ${data.error}`); - return; - } - - const row = JSON.parse(data.data); - await addRow(row); - } catch (error: any) { - showError(`Failed to add row: ${error.message}`); - } - }, - [addRow, showError], - ); - - const onRemoveRow = useCallback( - async (index: number) => { - await removeRow(index); - }, - [removeRow], - ); - - useEffect(() => { - if (table.data?.rows) { - const rows = table.data.rows.items.map((row) => { - return { - data: row, - error: "", - }; - }); - setRows(rows); - } - }, [table.data?.rows]); - - return ( -
-
-
-
- -
- - {table.data && ( -
- -
- )} -
-
-
- ); - }, -); diff --git a/apps/wing-console/console/ui/src/features/resource-interaction-view.tsx b/apps/wing-console/console/ui/src/features/resource-interaction-view.tsx index b8a0aa3e9ac..594de088e68 100644 --- a/apps/wing-console/console/ui/src/features/resource-interaction-view.tsx +++ b/apps/wing-console/console/ui/src/features/resource-interaction-view.tsx @@ -3,7 +3,6 @@ import { memo, useCallback } from "react"; import { ApiInteractionView } from "./api-interaction-view.js"; import { BucketInteractionView } from "./bucket-interaction-view.js"; import { CounterInteractionView } from "./counter-interaction-view.js"; -import { DynamodbTableInteractionView } from "./dynamodb-table-interaction-view.js"; import { EndpointInteractionView } from "./endpoint-interaction-view.js"; import { FunctionInteractionView } from "./function-interaction-view.js"; import { QueueInteractionView } from "./queue-interaction-view.js"; @@ -57,9 +56,6 @@ export const ResourceInteractionView = memo( case "@winglang/sdk.cloud.Website": { return ; } - case "@winglang/sdk.ex.DynamodbTable": { - return ; - } case "@winglang/sdk.cloud.Endpoint": { return ; } diff --git a/apps/wing-console/console/ui/src/services/use-dynamodb-table.ts b/apps/wing-console/console/ui/src/services/use-dynamodb-table.ts deleted file mode 100644 index 29ba199fc98..00000000000 --- a/apps/wing-console/console/ui/src/services/use-dynamodb-table.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { useCallback, useMemo } from "react"; - -import { trpc } from "./trpc.js"; - -export interface UseTableOptions { - resourcePath: string; -} - -export const useDynamodbTable = ({ resourcePath }: UseTableOptions) => { - const table = trpc["dynamodb-table.info"].useQuery({ resourcePath }); - const tableInsert = trpc["dynamodb-table.insert"].useMutation(); - const tableDelete = trpc["dynamodb-table.delete"].useMutation(); - - const addRow = useCallback( - async (row: any) => { - await tableInsert.mutateAsync({ - resourcePath, - data: row, - }); - }, - [tableInsert, resourcePath], - ); - - const removeRow = useCallback( - async (index: number) => { - const row = table.data?.rows.items[index]; - if (!row) { - return; - } - await tableDelete.mutateAsync({ - resourcePath, - data: row, - }); - }, - [tableDelete, resourcePath, table.data?.rows], - ); - - const loading = useMemo(() => { - return table.isFetching || tableInsert.isLoading || tableDelete.isLoading; - }, [tableInsert.isLoading, tableDelete.isLoading, table.isFetching]); - - return { - table, - addRow, - removeRow, - loading, - }; -}; diff --git a/apps/wing-console/console/ui/src/ui/dynamodb-table-interaction.tsx b/apps/wing-console/console/ui/src/ui/dynamodb-table-interaction.tsx deleted file mode 100644 index 72f68ee7a1f..00000000000 --- a/apps/wing-console/console/ui/src/ui/dynamodb-table-interaction.tsx +++ /dev/null @@ -1,330 +0,0 @@ -import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline"; -import type { Column } from "@wingconsole/design-system"; -import { - SpinnerLoader, - useTheme, - getInputType, - TableRow, -} from "@wingconsole/design-system"; -import classNames from "classnames"; -import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; - -export type RowData = Record; - -export type Row = { - data: RowData; - error?: string; -}; - -export type RawRow = { - data: string; - error?: string; -}; - -export interface TableInteractionProps { - hashKey: string; - rangeKey?: string; - rows?: Row[]; - onAddRow?: (row: RawRow) => void; - onRemoveRow?: (index: number) => void; - disabled?: boolean; - readonly?: boolean; - loading?: boolean; -} - -export const DynamodbTableInteraction = memo( - ({ - hashKey, - rangeKey, - rows = [], - onAddRow = (row: RawRow) => {}, - onRemoveRow = (index: number) => {}, - disabled = false, - readonly = false, - loading = false, - }: TableInteractionProps) => { - const { theme } = useTheme(); - - const [newRow, setNewRow] = useState({ data: "", error: "" }); - const [internalRows, setInternalRows] = useState([]); - const inputRef = useRef(null); - - const columns = useMemo(() => { - let keys = new Set(); - for (let row of rows) { - for (let key of Object.keys(row.data)) { - if (key !== hashKey && key !== rangeKey) { - keys.add(key); - } - } - } - - const result: Column[] = [ - { - name: hashKey, - type: "string", - }, - ...(rangeKey - ? [ - { - name: rangeKey, - type: "string", - }, - ] - : []), - ]; - - for (let key of [...keys.values()].sort()) { - result.push({ name: key, type: "string" }); - } - - return result; - }, [hashKey, rangeKey, rows]); - - const addRow = useCallback(async () => { - onAddRow(newRow); - }, [newRow, onAddRow]); - - const updateNewRow = useCallback( - (newValue: any) => { - let error = ""; - try { - const row = JSON.parse(newValue); - if (row[hashKey] === undefined) { - error = `missing hash key ${hashKey}`; - } else if (rangeKey && row[rangeKey] === undefined) { - error = `missing range key ${rangeKey}`; - } - } catch { - error = "not a valid JSON"; - } - - setNewRow({ - data: newValue, - error, - }); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [newRow, hashKey, rangeKey], - ); - - useEffect(() => { - setNewRow({ data: "", error: "" }); - setInternalRows(rows); - }, [rows]); - - useEffect(() => { - inputRef.current?.focus(); - }, [internalRows.length]); - - const headerSuffix = useCallback( - (name: string) => { - switch (name) { - case hashKey: - case rangeKey: { - return "*"; - } - default: { - return ""; - } - } - }, - [hashKey, rangeKey], - ); - - return ( -
-
- {loading && ( -
-
- -
-
- )} - - - - {columns.map(({ name, type }, index) => ( - - ))} - - - - - {internalRows.length === 0 && ( - - - - )} - {internalRows.map(({ data: row, error }, index) => ( - - {!readonly && ( - - )} - - } - dataTestid={`ex.DynamodbTable:row-${index}`} - /> - ))} - <> - - - - -
- {`${name}${headerSuffix(name)}`} -
- No rows -
-
-
- NEW ROW -
-
-
-
-