Skip to content

Commit a044555

Browse files
author
wellingtonjr3873
committed
merge conflict
2 parents bd13126 + be56347 commit a044555

File tree

224 files changed

+35772
-158
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

224 files changed

+35772
-158
lines changed

MAINTAINERS.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ viktormarinho
44
mcandeia
55
pedrofrxncx
66
lucis
7+
vitoUwu
8+
IncognitaDev
9+
stherzada

NewAppPrompt.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ const action = async (
301301
export default action;
302302
```
303303

304+
If a method has no props, just don't type the Props. Don't export an empty
305+
interface.
306+
304307
### deco.ts
305308

306309
In root `deco.ts`, add a new entry for the newly created app.

airtable/actions/createField.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import type { AppContext } from "../mod.ts";
2+
import type { CreateFieldBody, Field } from "../types.ts";
3+
4+
// Props will be CreateFieldBody plus baseId and tableId
5+
interface Props extends CreateFieldBody {
6+
/**
7+
* @title Base ID
8+
*/
9+
baseId: string;
10+
11+
/**
12+
* @title Table ID
13+
* @description The ID of the table to add the field to.
14+
*/
15+
tableId: string;
16+
/**
17+
* @title API Key
18+
*/
19+
apiKey?: string;
20+
// name, type, description, options are inherited from CreateFieldBody
21+
}
22+
23+
/**
24+
* @title Create Airtable Field
25+
* @description Creates a new field in a specified table (Metadata API).
26+
* @see https://airtable.com/developers/web/api/create-field
27+
*/
28+
const action = async (
29+
props: Props,
30+
req: Request,
31+
ctx: AppContext,
32+
): Promise<Field | Response> => {
33+
const { baseId, tableId, name, type, description, options, apiKey } = props;
34+
35+
const authHeader = req.headers.get("Authorization")?.split(" ")[1];
36+
const resolvedApiKey = authHeader || apiKey;
37+
38+
if (!resolvedApiKey) {
39+
return new Response("API Key is required", { status: 403 });
40+
}
41+
42+
const body: CreateFieldBody = {
43+
name,
44+
type,
45+
};
46+
if (description) {
47+
body.description = description;
48+
}
49+
if (options) {
50+
body.options = options;
51+
}
52+
53+
const response = await ctx.api(resolvedApiKey)
54+
["POST /v0/meta/bases/:baseId/tables/:tableId/fields"](
55+
{ baseId, tableId }, // URL params
56+
{ body }, // Request body
57+
);
58+
59+
if (!response.ok) {
60+
throw new Error(`Error creating field: ${response.statusText}`);
61+
}
62+
63+
return response.json();
64+
};
65+
66+
export default action;

airtable/actions/createRecord.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import type { AppContext } from "../mod.ts";
2+
import type { AirtableRecord, FieldSet } from "../types.ts";
3+
4+
interface Props {
5+
/**
6+
* @title Base ID
7+
*/
8+
baseId: string;
9+
10+
/**
11+
* @title Table ID or Name
12+
*/
13+
tableIdOrName: string;
14+
15+
/**
16+
* @title Record Fields
17+
* @description The fields for the new record.
18+
*/
19+
fields: FieldSet;
20+
21+
/**
22+
* @title Typecast
23+
* @description Optional. If true, Airtable will attempt to convert cell values to the appropriate type.
24+
*/
25+
typecast?: boolean;
26+
27+
/**
28+
* @title API Key
29+
*/
30+
apiKey?: string;
31+
}
32+
33+
/**
34+
* @title Create Airtable Record
35+
* @description Creates a new record in a specified table.
36+
*/
37+
const action = async (
38+
props: Props,
39+
req: Request,
40+
ctx: AppContext,
41+
): Promise<AirtableRecord | Response> => {
42+
const { baseId, tableIdOrName, fields, typecast, apiKey } = props;
43+
44+
const authHeader = req.headers.get("Authorization")?.split(" ")[1];
45+
const resolvedApiKey = authHeader || apiKey;
46+
47+
if (!resolvedApiKey) {
48+
return new Response("API Key is required", { status: 403 });
49+
}
50+
51+
const body = {
52+
fields,
53+
...(typecast !== undefined && { typecast }),
54+
};
55+
56+
const response = await ctx.api(resolvedApiKey)
57+
["POST /v0/:baseId/:tableIdOrName"](
58+
{ baseId, tableIdOrName }, // URL parameters
59+
{ body }, // Request body and other options
60+
);
61+
62+
if (!response.ok) {
63+
throw new Error(`Error creating record: ${response.statusText}`);
64+
}
65+
66+
return response.json();
67+
};
68+
69+
export default action;

airtable/actions/createTable.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import type { AppContext } from "../mod.ts";
2+
import type { CreateTableBody, Field, Table } from "../types.ts";
3+
4+
interface Props {
5+
/**
6+
* @title Base ID
7+
*/
8+
baseId: string;
9+
10+
/**
11+
* @title Table Name
12+
*/
13+
name: string;
14+
15+
/**
16+
* @title Table Description
17+
* @description Optional description for the new table.
18+
*/
19+
description?: string;
20+
21+
/**
22+
* @title Table Fields
23+
* @description Array of field definitions for the new table.
24+
* @see https://airtable.com/developers/web/api/field-model
25+
*/
26+
fields: Array<Omit<Field, "id">>; // When creating a table, field IDs are not provided for new fields.
27+
28+
/**
29+
* @title Primary Field ID or Name
30+
* @description Optional. The name or ID of the field to be set as primary.
31+
* If not provided, Airtable usually defaults to the first field or requires one with a supported type.
32+
*/
33+
primaryFieldNameOrId?: string; // Airtable API for create table can take primaryFieldId. This simplifies it to a name.
34+
// This will need to be translated to the correct structure for CreateTableBody.fields if needed
35+
// Or CreateTableBody might need primaryFieldId directly.
36+
// For simplicity, let's assume CreateTableBody handles fields definitions correctly.
37+
}
38+
39+
/**
40+
* @title API Key
41+
*/
42+
interface PropsWithApiKey extends Props {
43+
apiKey?: string;
44+
}
45+
46+
/**
47+
* @title Create Airtable Table
48+
* @description Creates a new table within a specified base (Metadata API).
49+
*/
50+
const action = async (
51+
props: PropsWithApiKey,
52+
req: Request,
53+
ctx: AppContext,
54+
): Promise<Table | Response> => {
55+
const { baseId, name, description, fields, apiKey } = props;
56+
57+
const authHeader = req.headers.get("Authorization")?.split(" ")[1];
58+
const resolvedApiKey = authHeader || apiKey;
59+
60+
if (!resolvedApiKey) {
61+
return new Response("API Key is required", { status: 403 });
62+
}
63+
64+
// The client expects `body: CreateTableBody`
65+
// CreateTableBody is { name: string, description?: string, fields: Field[], primaryFieldId?: string }
66+
// Our Props.fields is Array<Omit<Field, "id">>. This is compatible with Field[] where id is optional.
67+
const body: CreateTableBody = {
68+
name,
69+
fields: fields as Field[], // Cast Omit<Field, "id">[] to Field[]
70+
};
71+
72+
if (description) {
73+
body.description = description;
74+
}
75+
// Handling primaryFieldNameOrId would typically involve finding that field in the `fields` array
76+
// (if it's a name) and then setting its ID to `body.primaryFieldId` IF the API expects that.
77+
// The Airtable API for creating tables usually infers the primary field or requires one of the fields
78+
// to be of a primary-compatible type.
79+
// The `CreateTableBody` includes `primaryFieldId?: string;`. If the user provides it, we pass it.
80+
// Let's adjust Props to take primaryFieldId to align better with CreateTableBody
81+
// For now, this example will omit direct primaryFieldId setting from Props to simplify, assuming field definitions suffice or a default is used.
82+
// If `primaryFieldNameOrId` was intended to be `primaryFieldId` from `CreateTableBody` it should be named so in `Props`.
83+
84+
const response = await ctx.api(resolvedApiKey)
85+
["POST /v0/meta/bases/:baseId/tables"](
86+
{ baseId }, // URL params
87+
{ body }, // Request body
88+
);
89+
90+
if (!response.ok) {
91+
throw new Error(`Error creating table: ${response.statusText}`);
92+
}
93+
94+
return response.json();
95+
};
96+
97+
export default action;

airtable/actions/deleteRecords.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { AppContext } from "../mod.ts";
2+
3+
interface Props {
4+
/**
5+
* @title Base ID
6+
*/
7+
baseId: string;
8+
9+
/**
10+
* @title Table ID or Name
11+
*/
12+
tableIdOrName: string;
13+
14+
/**
15+
* @title Record IDs to Delete
16+
* @description An array of record IDs to be deleted.
17+
*/
18+
recordIds: string[];
19+
20+
/**
21+
* @title API Key
22+
*/
23+
apiKey?: string;
24+
}
25+
26+
/**
27+
* @title Delete Airtable Records
28+
* @description Deletes one or more records from a specified table.
29+
*/
30+
const action = async (
31+
props: Props,
32+
req: Request,
33+
ctx: AppContext,
34+
): Promise<{ records: Array<{ id: string; deleted: boolean }> } | Response> => {
35+
const { baseId, tableIdOrName, recordIds, apiKey } = props;
36+
37+
const authHeader = req.headers.get("Authorization")?.split(" ")[1];
38+
const resolvedApiKey = authHeader || apiKey;
39+
40+
if (!resolvedApiKey) {
41+
return new Response("API Key is required", { status: 403 });
42+
}
43+
44+
// The client expects searchParams: { "records[]": string[] }
45+
// The parameters to the client call should be flat, including URL params and searchParams
46+
const params = {
47+
baseId,
48+
tableIdOrName,
49+
"records[]": recordIds,
50+
};
51+
52+
const response = await ctx.api(resolvedApiKey)
53+
["DELETE /v0/:baseId/:tableIdOrName"](
54+
params,
55+
);
56+
57+
if (!response.ok) {
58+
throw new Error(`Error deleting records: ${response.statusText}`);
59+
}
60+
61+
return response.json();
62+
};
63+
64+
export default action;

airtable/actions/updateField.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { AppContext } from "../mod.ts";
2+
import type { Field, UpdateFieldBody } from "../types.ts";
3+
4+
// Props will be UpdateFieldBody plus baseId, tableId, and fieldId
5+
interface Props extends UpdateFieldBody {
6+
/**
7+
* @title Base ID
8+
*/
9+
baseId: string;
10+
11+
/**
12+
* @title Table ID
13+
*/
14+
tableId: string;
15+
16+
/**
17+
* @title Field ID
18+
* @description The ID of the field to update.
19+
*/
20+
fieldId: string;
21+
/**
22+
* @title API Key
23+
*/
24+
apiKey?: string;
25+
// name, description are inherited from UpdateFieldBody
26+
// type and options changes are complex and generally not advised via simple updates.
27+
}
28+
29+
/**
30+
* @title Update Airtable Field
31+
* @description Updates an existing field's properties like name or description (Metadata API).
32+
* @see https://airtable.com/developers/web/api/update-field
33+
*/
34+
const action = async (
35+
props: Props,
36+
req: Request,
37+
ctx: AppContext,
38+
): Promise<Field | Response> => {
39+
const { baseId, tableId, fieldId, name, description, apiKey } = props;
40+
41+
const authHeader = req.headers.get("Authorization")?.split(" ")[1];
42+
const resolvedApiKey = authHeader || apiKey;
43+
44+
if (!resolvedApiKey) {
45+
return new Response("API Key is required", { status: 403 });
46+
}
47+
48+
const body: UpdateFieldBody = {};
49+
if (name) {
50+
body.name = name;
51+
}
52+
if (description) {
53+
body.description = description;
54+
}
55+
56+
if (Object.keys(body).length === 0) {
57+
throw new Error(
58+
"No updates provided for the field. Please specify name or description.",
59+
);
60+
}
61+
62+
const response = await ctx.api(resolvedApiKey)
63+
["PATCH /v0/meta/bases/:baseId/tables/:tableId/fields/:fieldId"](
64+
{ baseId, tableId, fieldId }, // URL params
65+
{ body }, // Request body
66+
);
67+
68+
if (!response.ok) {
69+
throw new Error(`Error updating field: ${response.statusText}`);
70+
}
71+
72+
return response.json();
73+
};
74+
75+
export default action;

0 commit comments

Comments
 (0)