runline 0.11.6 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/actions.js +3 -1
- package/dist/core/engine.js +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/plugin/api.d.ts +2 -1
- package/dist/plugin/types.d.ts +2 -0
- package/dist/plugins/_shared/googleSchemas.js +23 -0
- package/dist/plugins/actionNetwork/src/index.js +23 -0
- package/dist/plugins/activeCampaign/src/index.js +48 -0
- package/dist/plugins/adalo/src/index.js +5 -0
- package/dist/plugins/affinity/src/index.js +16 -0
- package/dist/plugins/agileCrm/src/index.js +15 -0
- package/dist/plugins/airtable/src/index.js +10 -0
- package/dist/plugins/airtop/src/index.js +24 -0
- package/dist/plugins/apiTemplateIo/src/index.js +4 -0
- package/dist/plugins/asana/src/index.js +22 -0
- package/dist/plugins/autopilot/src/index.js +11 -0
- package/dist/plugins/bambooHr/src/index.js +11 -0
- package/dist/plugins/bannerbear/src/index.js +4 -0
- package/dist/plugins/baserow/src/index.js +8 -0
- package/dist/plugins/beeminder/src/index.js +18 -0
- package/dist/plugins/bitly/src/index.js +3 -0
- package/dist/plugins/bitwarden/src/index.js +19 -0
- package/dist/plugins/box/src/index.js +11 -0
- package/dist/plugins/brandfetch/src/index.js +5 -0
- package/dist/plugins/brevo/src/index.js +15 -0
- package/dist/plugins/bubble/src/index.js +5 -0
- package/dist/plugins/chargebee/src/index.js +5 -0
- package/dist/plugins/circleci/src/index.js +3 -0
- package/dist/plugins/ciscoWebex/src/index.js +10 -0
- package/dist/plugins/clearbit/src/index.js +3 -0
- package/dist/plugins/clickup/src/index.js +61 -0
- package/dist/plugins/clockify/src/index.js +25 -0
- package/dist/plugins/cloudflare/src/index.js +4 -0
- package/dist/plugins/cockpit/src/index.js +5 -0
- package/dist/plugins/coda/src/index.js +18 -0
- package/dist/plugins/coingecko/src/index.js +10 -0
- package/dist/plugins/contentful/src/index.js +7 -0
- package/dist/plugins/convertkit/src/index.js +16 -0
- package/dist/plugins/copper/src/index.js +7 -0
- package/dist/plugins/cortex/src/index.js +4 -0
- package/dist/plugins/currents/src/index.js +22 -0
- package/dist/plugins/customerIo/src/index.js +9 -0
- package/dist/plugins/databricks/src/index.js +34 -0
- package/dist/plugins/deepl/src/index.js +2 -0
- package/dist/plugins/demio/src/index.js +4 -0
- package/dist/plugins/dhl/src/index.js +1 -0
- package/dist/plugins/discord/src/index.js +13 -0
- package/dist/plugins/discourse/src/index.js +16 -0
- package/dist/plugins/disqus/src/index.js +4 -0
- package/dist/plugins/docker/src/index.js +5 -0
- package/dist/plugins/drift/src/index.js +5 -0
- package/dist/plugins/dropbox/src/index.js +9 -0
- package/dist/plugins/dropcontact/src/index.js +2 -0
- package/dist/plugins/egoi/src/index.js +4 -0
- package/dist/plugins/elasticsearch/src/index.js +9 -0
- package/dist/plugins/emelia/src/index.js +9 -0
- package/dist/plugins/erpnext/src/index.js +5 -0
- package/dist/plugins/facebookGraph/src/index.js +1 -0
- package/dist/plugins/freshdesk/src/index.js +10 -0
- package/dist/plugins/freshservice/src/index.js +7 -0
- package/dist/plugins/freshworksCrm/src/index.js +7 -0
- package/dist/plugins/getresponse/src/index.js +5 -0
- package/dist/plugins/ghost/src/index.js +5 -0
- package/dist/plugins/github/src/index.js +37 -0
- package/dist/plugins/gitlab/src/index.js +17 -0
- package/dist/plugins/gmail/src/index.js +200 -184
- package/dist/plugins/gong/src/index.js +4 -0
- package/dist/plugins/googleAppsScript/src/index.js +98 -43
- package/dist/plugins/googleCalendar/src/index.js +329 -250
- package/dist/plugins/googleContacts/src/index.js +144 -145
- package/dist/plugins/googleDocs/src/documents.js +31 -38
- package/dist/plugins/googleDocs/src/formatting.js +51 -47
- package/dist/plugins/googleDocs/src/images.js +23 -26
- package/dist/plugins/googleDocs/src/shared.js +55 -0
- package/dist/plugins/googleDocs/src/structure.js +111 -123
- package/dist/plugins/googleDocs/src/tables.js +103 -154
- package/dist/plugins/googleDocs/src/tabs.js +27 -23
- package/dist/plugins/googleDocs/src/text.js +106 -136
- package/dist/plugins/googleDrive/src/index.js +461 -408
- package/dist/plugins/googleImage/src/index.js +14 -16
- package/dist/plugins/googleSheets/src/index.js +527 -339
- package/dist/plugins/googleSlides/src/index.js +92 -72
- package/dist/plugins/googleTasks/src/index.js +94 -92
- package/dist/plugins/gotify/src/index.js +3 -0
- package/dist/plugins/gotowebinar/src/index.js +20 -0
- package/dist/plugins/grafana/src/index.js +17 -0
- package/dist/plugins/graphql/src/index.js +2 -0
- package/dist/plugins/grist/src/index.js +4 -0
- package/dist/plugins/hackernews/src/index.js +6 -0
- package/dist/plugins/halopsa/src/index.js +5 -0
- package/dist/plugins/harvest/src/index.js +14 -0
- package/dist/plugins/helpscout/src/index.js +13 -0
- package/dist/plugins/highlevel/src/index.js +17 -0
- package/dist/plugins/homeAssistant/src/index.js +13 -0
- package/dist/plugins/hubspot/src/index.js +14 -0
- package/dist/plugins/humanticAi/src/index.js +3 -0
- package/dist/plugins/hunter/src/index.js +3 -0
- package/dist/plugins/intercom/src/index.js +10 -0
- package/dist/plugins/iterable/src/index.js +6 -0
- package/dist/plugins/jenkins/src/index.js +11 -0
- package/dist/plugins/jira/src/index.js +16 -0
- package/dist/plugins/keap/src/index.js +28 -0
- package/dist/plugins/kobotoolbox/src/index.js +17 -0
- package/dist/plugins/lemlist/src/index.js +15 -0
- package/dist/plugins/linear/src/attachments.js +6 -0
- package/dist/plugins/linear/src/comments.js +5 -0
- package/dist/plugins/linear/src/cycles.js +2 -0
- package/dist/plugins/linear/src/initiatives.js +5 -0
- package/dist/plugins/linear/src/issues.js +14 -0
- package/dist/plugins/linear/src/labels.js +5 -0
- package/dist/plugins/linear/src/organization.js +1 -0
- package/dist/plugins/linear/src/projects.js +11 -0
- package/dist/plugins/linear/src/shared.js +2 -0
- package/dist/plugins/linear/src/states.js +2 -0
- package/dist/plugins/linear/src/teams.js +3 -0
- package/dist/plugins/linear/src/users.js +2 -0
- package/dist/plugins/linear/src/views.js +4 -0
- package/dist/plugins/linear/src/webhooks.js +4 -0
- package/dist/plugins/lingvanex/src/index.js +1 -0
- package/dist/plugins/linkedin/src/index.js +1 -0
- package/dist/plugins/lonescale/src/index.js +4 -0
- package/dist/plugins/magento/src/index.js +15 -0
- package/dist/plugins/mailcheck/src/index.js +1 -0
- package/dist/plugins/mailchimp/src/index.js +14 -0
- package/dist/plugins/mailerlite/src/index.js +4 -0
- package/dist/plugins/mailgun/src/index.js +1 -0
- package/dist/plugins/mailjet/src/index.js +3 -0
- package/dist/plugins/mandrill/src/index.js +2 -0
- package/dist/plugins/marketstack/src/index.js +3 -0
- package/dist/plugins/matrix/src/index.js +10 -0
- package/dist/plugins/mattermost/src/index.js +19 -0
- package/dist/plugins/mautic/src/index.js +20 -0
- package/dist/plugins/medium/src/index.js +3 -0
- package/dist/plugins/messagebird/src/index.js +2 -0
- package/dist/plugins/metabase/src/index.js +10 -0
- package/dist/plugins/microsoftCalendar/src/index.js +2 -0
- package/dist/plugins/microsoftFiles/src/index.js +5 -0
- package/dist/plugins/microsoftMail/src/index.js +4 -0
- package/dist/plugins/misp/src/index.js +44 -0
- package/dist/plugins/mocean/src/index.js +2 -0
- package/dist/plugins/monday/src/index.js +18 -0
- package/dist/plugins/monicaCrm/src/index.js +5 -0
- package/dist/plugins/msg91/src/index.js +1 -0
- package/dist/plugins/nasa/src/index.js +7 -0
- package/dist/plugins/netlify/src/index.js +7 -0
- package/dist/plugins/netscalerAdc/src/index.js +3 -0
- package/dist/plugins/nextcloud/src/index.js +13 -0
- package/dist/plugins/nocodb/src/index.js +5 -0
- package/dist/plugins/node/src/index.js +38 -0
- package/dist/plugins/notion/src/index.js +14 -0
- package/dist/plugins/npm/src/index.js +5 -0
- package/dist/plugins/odoo/src/index.js +6 -0
- package/dist/plugins/okta/src/index.js +5 -0
- package/dist/plugins/oneSimpleApi/src/index.js +10 -0
- package/dist/plugins/onfleet/src/index.js +24 -0
- package/dist/plugins/openThesaurus/src/index.js +1 -0
- package/dist/plugins/openai/src/index.js +1 -0
- package/dist/plugins/openweathermap/src/index.js +2 -0
- package/dist/plugins/oura/src/index.js +2 -0
- package/dist/plugins/paddle/src/index.js +9 -0
- package/dist/plugins/pagerduty/src/index.js +9 -0
- package/dist/plugins/parallel/src/index.js +1 -0
- package/dist/plugins/paypal/src/index.js +4 -0
- package/dist/plugins/peekalink/src/index.js +2 -0
- package/dist/plugins/phantombuster/src/index.js +5 -0
- package/dist/plugins/philipsHue/src/index.js +4 -0
- package/dist/plugins/pipedrive/src/index.js +14 -0
- package/dist/plugins/plivo/src/index.js +3 -0
- package/dist/plugins/postbin/src/index.js +6 -0
- package/dist/plugins/posthog/src/index.js +5 -0
- package/dist/plugins/profitwell/src/index.js +2 -0
- package/dist/plugins/pushbullet/src/index.js +4 -0
- package/dist/plugins/pushcut/src/index.js +1 -0
- package/dist/plugins/pushover/src/index.js +1 -0
- package/dist/plugins/quickbase/src/index.js +8 -0
- package/dist/plugins/quickbooks/src/index.js +5 -0
- package/dist/plugins/quickchart/src/index.js +1 -0
- package/dist/plugins/raindrop/src/index.js +13 -0
- package/dist/plugins/recraft/src/index.js +1 -0
- package/dist/plugins/reddit/src/index.js +10 -0
- package/dist/plugins/replicate/src/index.js +1 -0
- package/dist/plugins/rocketchat/src/index.js +1 -0
- package/dist/plugins/rundeck/src/index.js +2 -0
- package/dist/plugins/salesforce/src/metadata.js +4 -0
- package/dist/plugins/salesforce/src/query.js +5 -0
- package/dist/plugins/salesforce/src/sobjects.js +12 -0
- package/dist/plugins/salesmate/src/index.js +5 -0
- package/dist/plugins/securityScorecard/src/index.js +14 -0
- package/dist/plugins/segment/src/index.js +4 -0
- package/dist/plugins/sendgrid/src/index.js +10 -0
- package/dist/plugins/sendy/src/index.js +6 -0
- package/dist/plugins/sentry/src/index.js +24 -0
- package/dist/plugins/servicenow/src/index.js +10 -0
- package/dist/plugins/shiftLabs/src/index.js +6 -0
- package/dist/plugins/shiftLabs/src/issues.js +4 -0
- package/dist/plugins/shiftLabs/src/pages.js +10 -0
- package/dist/plugins/shiftLabs/src/shared.js +2 -0
- package/dist/plugins/shiftLabs/src/transcription.js +203 -0
- package/dist/plugins/shopify/src/index.js +10 -0
- package/dist/plugins/signl4/src/index.js +2 -0
- package/dist/plugins/slack/src/index.js +38 -0
- package/dist/plugins/sms77/src/index.js +2 -0
- package/dist/plugins/splunk/src/index.js +16 -0
- package/dist/plugins/spotify/src/index.js +30 -0
- package/dist/plugins/stackby/src/index.js +4 -0
- package/dist/plugins/steel/src/browser.js +7 -0
- package/dist/plugins/steel/src/captchas.js +3 -0
- package/dist/plugins/steel/src/credentials.js +4 -0
- package/dist/plugins/steel/src/extensions.js +5 -0
- package/dist/plugins/steel/src/files.js +10 -0
- package/dist/plugins/steel/src/profiles.js +4 -0
- package/dist/plugins/steel/src/sessions.js +11 -0
- package/dist/plugins/storyblok/src/index.js +7 -0
- package/dist/plugins/strapi/src/index.js +5 -0
- package/dist/plugins/strava/src/index.js +6 -0
- package/dist/plugins/stripe/src/index.js +20 -0
- package/dist/plugins/supabase/src/index.js +5 -0
- package/dist/plugins/syncromsp/src/index.js +20 -0
- package/dist/plugins/tapfiliate/src/index.js +11 -0
- package/dist/plugins/telegram/src/index.js +21 -0
- package/dist/plugins/thehive/src/index.js +23 -0
- package/dist/plugins/thehiveProject/src/index.js +31 -0
- package/dist/plugins/todoist/src/index.js +31 -0
- package/dist/plugins/together/src/index.js +1 -0
- package/dist/plugins/travisci/src/index.js +5 -0
- package/dist/plugins/trello/src/index.js +37 -0
- package/dist/plugins/twake/src/index.js +1 -0
- package/dist/plugins/twilio/src/index.js +2 -0
- package/dist/plugins/twist/src/index.js +22 -0
- package/dist/plugins/twitter/src/index.js +8 -0
- package/dist/plugins/unleashedSoftware/src/index.js +3 -0
- package/dist/plugins/uplead/src/index.js +2 -0
- package/dist/plugins/uproc/src/index.js +1 -0
- package/dist/plugins/uptimerobot/src/index.js +22 -0
- package/dist/plugins/urlscanio/src/index.js +3 -0
- package/dist/plugins/vercel/src/account.js +1 -0
- package/dist/plugins/vercel/src/deployments.js +5 -0
- package/dist/plugins/vercel/src/env.js +4 -0
- package/dist/plugins/vercel/src/projects.js +2 -0
- package/dist/plugins/vercel/src/shared.js +1 -0
- package/dist/plugins/vero/src/index.js +6 -0
- package/dist/plugins/vonage/src/index.js +1 -0
- package/dist/plugins/wekan/src/index.js +24 -0
- package/dist/plugins/woocommerce/src/index.js +5 -0
- package/dist/plugins/wordpress/src/index.js +10 -0
- package/dist/plugins/xai/src/index.js +1 -0
- package/dist/plugins/xero/src/index.js +8 -0
- package/dist/plugins/yourls/src/index.js +3 -0
- package/dist/plugins/zammad/src/index.js +12 -0
- package/dist/plugins/zendesk/src/index.js +18 -0
- package/dist/plugins/zoho/src/index.js +6 -0
- package/dist/plugins/zoom/src/index.js +5 -0
- package/dist/plugins/zulip/src/index.js +15 -0
- package/dist/sdk.d.ts +2 -1
- package/dist/sdk.js +1 -0
- package/package.json +1 -1
|
@@ -22,14 +22,57 @@
|
|
|
22
22
|
* sheet.deleteDimension — drop N rows or columns starting at an index
|
|
23
23
|
* sheet.batchUpdate — raw passthrough to spreadsheets:batchUpdate
|
|
24
24
|
*
|
|
25
|
+
* chart.add / chart.update / chart.delete
|
|
26
|
+
* namedRange.add / namedRange.delete
|
|
27
|
+
* protectedRange.add / protectedRange.delete
|
|
28
|
+
* conditionalFormat.add / conditionalFormat.delete
|
|
29
|
+
* dataValidation.set
|
|
30
|
+
*
|
|
25
31
|
* Features: auto-column-add on update/upsert, multi-row
|
|
26
32
|
* batchUpdate, RAW vs USER_ENTERED value input, appending via
|
|
27
33
|
* values:append or PUT at lastRow+1, keepFirstRow on clear.
|
|
28
34
|
* Filtering is intentionally the caller's job — `read` returns
|
|
29
35
|
* raw rows / objects and callers post-filter.
|
|
30
36
|
*/
|
|
37
|
+
import * as t from "typebox";
|
|
31
38
|
import { googleAccessToken } from "../../_shared/googleAuth.js";
|
|
39
|
+
import { Id, JsonValue, NonEmptyString, NonNegativeInteger, PositiveInteger, RawGoogleObject, StringArray, stringEnum, } from "../../_shared/googleSchemas.js";
|
|
32
40
|
const ROW_NUMBER = "row_number";
|
|
41
|
+
const sheetReferenceSchema = t.Union([NonEmptyString, NonNegativeInteger]);
|
|
42
|
+
const cellValueSchema = t.Union([
|
|
43
|
+
t.String(),
|
|
44
|
+
t.Number(),
|
|
45
|
+
t.Boolean(),
|
|
46
|
+
t.Null(),
|
|
47
|
+
]);
|
|
48
|
+
const objectRowSchema = t.Record(t.String(), JsonValue);
|
|
49
|
+
const rowsSchema = t.Union([
|
|
50
|
+
t.Array(t.Array(cellValueSchema)),
|
|
51
|
+
t.Array(objectRowSchema),
|
|
52
|
+
]);
|
|
53
|
+
const valueInputOptionSchema = stringEnum(["RAW", "USER_ENTERED"]);
|
|
54
|
+
const handlingExtraDataSchema = stringEnum([
|
|
55
|
+
"ignore",
|
|
56
|
+
"error",
|
|
57
|
+
"insertInNewColumn",
|
|
58
|
+
]);
|
|
59
|
+
const initialSheetSchema = t.Object({
|
|
60
|
+
title: NonEmptyString,
|
|
61
|
+
sheetId: t.Optional(NonNegativeInteger),
|
|
62
|
+
index: t.Optional(NonNegativeInteger),
|
|
63
|
+
sheetType: t.Optional(stringEnum(["GRID", "OBJECT", "DATA_SOURCE"])),
|
|
64
|
+
hidden: t.Optional(t.Boolean()),
|
|
65
|
+
rightToLeft: t.Optional(t.Boolean()),
|
|
66
|
+
gridProperties: t.Optional(t.Object({
|
|
67
|
+
rowCount: t.Optional(PositiveInteger),
|
|
68
|
+
columnCount: t.Optional(PositiveInteger),
|
|
69
|
+
frozenRowCount: t.Optional(NonNegativeInteger),
|
|
70
|
+
frozenColumnCount: t.Optional(NonNegativeInteger),
|
|
71
|
+
hideGridlines: t.Optional(t.Boolean()),
|
|
72
|
+
rowGroupControlAfter: t.Optional(t.Boolean()),
|
|
73
|
+
columnGroupControlAfter: t.Optional(t.Boolean()),
|
|
74
|
+
}, { additionalProperties: false })),
|
|
75
|
+
}, { additionalProperties: false });
|
|
33
76
|
// ─── Auth ────────────────────────────────────────────────────────
|
|
34
77
|
async function accessToken(ctx) {
|
|
35
78
|
return googleAccessToken(ctx, "googleSheets", SCOPES);
|
|
@@ -60,7 +103,8 @@ async function sheetsRequest(ctx, method, path, body, qs, baseOverride) {
|
|
|
60
103
|
},
|
|
61
104
|
};
|
|
62
105
|
if (body && Object.keys(body).length > 0) {
|
|
63
|
-
init.headers["Content-Type"] =
|
|
106
|
+
init.headers["Content-Type"] =
|
|
107
|
+
"application/json";
|
|
64
108
|
init.body = JSON.stringify(body);
|
|
65
109
|
}
|
|
66
110
|
const res = await fetch(url.toString(), init);
|
|
@@ -322,7 +366,13 @@ function a1RangeToGridRange(a1, sheetId) {
|
|
|
322
366
|
const startRow = parseInt(m[2], 10) - 1;
|
|
323
367
|
const endCol = columnLetterToNumber(m[3]);
|
|
324
368
|
const endRow = parseInt(m[4], 10);
|
|
325
|
-
return {
|
|
369
|
+
return {
|
|
370
|
+
sheetId,
|
|
371
|
+
startRowIndex: startRow,
|
|
372
|
+
endRowIndex: endRow,
|
|
373
|
+
startColumnIndex: startCol,
|
|
374
|
+
endColumnIndex: endCol,
|
|
375
|
+
};
|
|
326
376
|
}
|
|
327
377
|
export default function googleSheets(rl) {
|
|
328
378
|
rl.setName("googleSheets");
|
|
@@ -408,21 +458,14 @@ export default function googleSheets(rl) {
|
|
|
408
458
|
});
|
|
409
459
|
// ── Spreadsheet ───────────────────────────────────────
|
|
410
460
|
rl.registerAction("spreadsheet.create", {
|
|
461
|
+
access: "write",
|
|
411
462
|
description: "Create a new spreadsheet",
|
|
412
|
-
inputSchema: {
|
|
413
|
-
title:
|
|
414
|
-
sheets:
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
},
|
|
419
|
-
locale: { type: "string", required: false, description: "e.g. en_US" },
|
|
420
|
-
autoRecalc: {
|
|
421
|
-
type: "string",
|
|
422
|
-
required: false,
|
|
423
|
-
description: "ON_CHANGE | MINUTE | HOUR",
|
|
424
|
-
},
|
|
425
|
-
},
|
|
463
|
+
inputSchema: t.Object({
|
|
464
|
+
title: NonEmptyString,
|
|
465
|
+
sheets: t.Optional(t.Array(initialSheetSchema)),
|
|
466
|
+
locale: t.Optional(NonEmptyString),
|
|
467
|
+
autoRecalc: t.Optional(stringEnum(["ON_CHANGE", "MINUTE", "HOUR"])),
|
|
468
|
+
}, { additionalProperties: false }),
|
|
426
469
|
async execute(input, ctx) {
|
|
427
470
|
const p = (input ?? {});
|
|
428
471
|
const body = {
|
|
@@ -441,17 +484,14 @@ export default function googleSheets(rl) {
|
|
|
441
484
|
},
|
|
442
485
|
});
|
|
443
486
|
rl.registerAction("spreadsheet.get", {
|
|
487
|
+
access: "read",
|
|
444
488
|
description: "Get spreadsheet metadata (sheets, properties, optional grid data)",
|
|
445
|
-
inputSchema: {
|
|
446
|
-
spreadsheetId:
|
|
447
|
-
includeGridData:
|
|
448
|
-
ranges:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
description: "Limit the response to specific A1 ranges",
|
|
452
|
-
},
|
|
453
|
-
fields: { type: "string", required: false },
|
|
454
|
-
},
|
|
489
|
+
inputSchema: t.Object({
|
|
490
|
+
spreadsheetId: Id,
|
|
491
|
+
includeGridData: t.Optional(t.Boolean()),
|
|
492
|
+
ranges: t.Optional(StringArray),
|
|
493
|
+
fields: t.Optional(NonEmptyString),
|
|
494
|
+
}, { additionalProperties: false }),
|
|
455
495
|
async execute(input, ctx) {
|
|
456
496
|
const p = (input ?? {});
|
|
457
497
|
const qs = {};
|
|
@@ -465,8 +505,9 @@ export default function googleSheets(rl) {
|
|
|
465
505
|
},
|
|
466
506
|
});
|
|
467
507
|
rl.registerAction("spreadsheet.delete", {
|
|
508
|
+
access: "write",
|
|
468
509
|
description: "Delete a spreadsheet (via Drive API — requires drive.file scope)",
|
|
469
|
-
inputSchema: { spreadsheetId:
|
|
510
|
+
inputSchema: t.Object({ spreadsheetId: Id }, { additionalProperties: false }),
|
|
470
511
|
async execute(input, ctx) {
|
|
471
512
|
const p = (input ?? {});
|
|
472
513
|
await sheetsRequest(ctx, "DELETE", `/drive/v3/files/${p.spreadsheetId}`, undefined, undefined, "https://www.googleapis.com");
|
|
@@ -475,24 +516,26 @@ export default function googleSheets(rl) {
|
|
|
475
516
|
});
|
|
476
517
|
// ── Sheet tabs ────────────────────────────────────────
|
|
477
518
|
rl.registerAction("sheet.listTabs", {
|
|
519
|
+
access: "read",
|
|
478
520
|
description: "List sheet tabs in a spreadsheet",
|
|
479
|
-
inputSchema: { spreadsheetId:
|
|
521
|
+
inputSchema: t.Object({ spreadsheetId: Id }, { additionalProperties: false }),
|
|
480
522
|
async execute(input, ctx) {
|
|
481
523
|
const p = (input ?? {});
|
|
482
524
|
return getSheetProperties(ctx, p.spreadsheetId);
|
|
483
525
|
},
|
|
484
526
|
});
|
|
485
527
|
rl.registerAction("sheet.addTab", {
|
|
528
|
+
access: "write",
|
|
486
529
|
description: "Add a new sheet tab",
|
|
487
|
-
inputSchema: {
|
|
488
|
-
spreadsheetId:
|
|
489
|
-
title:
|
|
490
|
-
index:
|
|
491
|
-
sheetId:
|
|
492
|
-
hidden:
|
|
493
|
-
rightToLeft:
|
|
494
|
-
tabColor: {
|
|
495
|
-
},
|
|
530
|
+
inputSchema: t.Object({
|
|
531
|
+
spreadsheetId: Id,
|
|
532
|
+
title: NonEmptyString,
|
|
533
|
+
index: t.Optional(NonNegativeInteger),
|
|
534
|
+
sheetId: t.Optional(NonNegativeInteger),
|
|
535
|
+
hidden: t.Optional(t.Boolean()),
|
|
536
|
+
rightToLeft: t.Optional(t.Boolean()),
|
|
537
|
+
tabColor: t.Optional(t.String({ pattern: "^#?[0-9a-fA-F]{6}$" })),
|
|
538
|
+
}, { additionalProperties: false }),
|
|
496
539
|
async execute(input, ctx) {
|
|
497
540
|
const p = (input ?? {});
|
|
498
541
|
const properties = { title: p.title };
|
|
@@ -514,15 +557,12 @@ export default function googleSheets(rl) {
|
|
|
514
557
|
},
|
|
515
558
|
});
|
|
516
559
|
rl.registerAction("sheet.deleteTab", {
|
|
560
|
+
access: "write",
|
|
517
561
|
description: "Delete a sheet tab",
|
|
518
|
-
inputSchema: {
|
|
519
|
-
spreadsheetId:
|
|
520
|
-
sheet:
|
|
521
|
-
|
|
522
|
-
required: true,
|
|
523
|
-
description: "Tab title or numeric sheetId",
|
|
524
|
-
},
|
|
525
|
-
},
|
|
562
|
+
inputSchema: t.Object({
|
|
563
|
+
spreadsheetId: Id,
|
|
564
|
+
sheet: sheetReferenceSchema,
|
|
565
|
+
}, { additionalProperties: false }),
|
|
526
566
|
async execute(input, ctx) {
|
|
527
567
|
const p = (input ?? {});
|
|
528
568
|
const sheetId = await resolveSheetId(ctx, p.spreadsheetId, p.sheet);
|
|
@@ -534,41 +574,22 @@ export default function googleSheets(rl) {
|
|
|
534
574
|
});
|
|
535
575
|
// ── Read ──────────────────────────────────────────────
|
|
536
576
|
rl.registerAction("sheet.read", {
|
|
577
|
+
access: "read",
|
|
537
578
|
description: "Read values from a range. Returns a 2D array by default; set `asObjects=true` to pair rows with a header row and return objects.",
|
|
538
|
-
inputSchema: {
|
|
539
|
-
spreadsheetId:
|
|
540
|
-
range:
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
type: "number",
|
|
553
|
-
required: false,
|
|
554
|
-
description: "1-indexed first data row (default: headerRow + 1)",
|
|
555
|
-
},
|
|
556
|
-
valueRenderOption: {
|
|
557
|
-
type: "string",
|
|
558
|
-
required: false,
|
|
559
|
-
description: "FORMATTED_VALUE (default) | UNFORMATTED_VALUE | FORMULA",
|
|
560
|
-
},
|
|
561
|
-
dateTimeRenderOption: {
|
|
562
|
-
type: "string",
|
|
563
|
-
required: false,
|
|
564
|
-
description: "FORMATTED_STRING (default) | SERIAL_NUMBER",
|
|
565
|
-
},
|
|
566
|
-
includeRowNumber: {
|
|
567
|
-
type: "boolean",
|
|
568
|
-
required: false,
|
|
569
|
-
description: "Attach `row_number` to each object (asObjects only)",
|
|
570
|
-
},
|
|
571
|
-
},
|
|
579
|
+
inputSchema: t.Object({
|
|
580
|
+
spreadsheetId: Id,
|
|
581
|
+
range: NonEmptyString,
|
|
582
|
+
asObjects: t.Optional(t.Boolean()),
|
|
583
|
+
headerRow: t.Optional(PositiveInteger),
|
|
584
|
+
dataStartRow: t.Optional(PositiveInteger),
|
|
585
|
+
valueRenderOption: t.Optional(stringEnum([
|
|
586
|
+
"FORMATTED_VALUE",
|
|
587
|
+
"UNFORMATTED_VALUE",
|
|
588
|
+
"FORMULA",
|
|
589
|
+
])),
|
|
590
|
+
dateTimeRenderOption: t.Optional(stringEnum(["FORMATTED_STRING", "SERIAL_NUMBER"])),
|
|
591
|
+
includeRowNumber: t.Optional(t.Boolean()),
|
|
592
|
+
}, { additionalProperties: false }),
|
|
572
593
|
async execute(input, ctx) {
|
|
573
594
|
const p = (input ?? {});
|
|
574
595
|
const rows = await getValues(ctx, p.spreadsheetId, p.range, p.valueRenderOption ?? "FORMATTED_VALUE", p.dateTimeRenderOption ?? "FORMATTED_STRING");
|
|
@@ -590,40 +611,17 @@ export default function googleSheets(rl) {
|
|
|
590
611
|
});
|
|
591
612
|
// ── Append ────────────────────────────────────────────
|
|
592
613
|
rl.registerAction("sheet.append", {
|
|
614
|
+
access: "write",
|
|
593
615
|
description: "Append rows to the bottom. Pass `rows` as arrays (matching columns) or objects (keyed by header names; extra keys become new columns by default).",
|
|
594
|
-
inputSchema: {
|
|
595
|
-
spreadsheetId:
|
|
596
|
-
sheet:
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
required: true,
|
|
604
|
-
description: "Array of arrays, or array of objects",
|
|
605
|
-
},
|
|
606
|
-
headerRow: {
|
|
607
|
-
type: "number",
|
|
608
|
-
required: false,
|
|
609
|
-
description: "1-indexed header row (default: 1, used when rows are objects)",
|
|
610
|
-
},
|
|
611
|
-
valueInputOption: {
|
|
612
|
-
type: "string",
|
|
613
|
-
required: false,
|
|
614
|
-
description: "USER_ENTERED (default) | RAW",
|
|
615
|
-
},
|
|
616
|
-
handlingExtraData: {
|
|
617
|
-
type: "string",
|
|
618
|
-
required: false,
|
|
619
|
-
description: "insertInNewColumn (default) | ignore | error",
|
|
620
|
-
},
|
|
621
|
-
useAppend: {
|
|
622
|
-
type: "boolean",
|
|
623
|
-
required: false,
|
|
624
|
-
description: "Use values:append (safer w/ formulas but rewrites filters) instead of PUT at lastRow+1",
|
|
625
|
-
},
|
|
626
|
-
},
|
|
616
|
+
inputSchema: t.Object({
|
|
617
|
+
spreadsheetId: Id,
|
|
618
|
+
sheet: sheetReferenceSchema,
|
|
619
|
+
rows: rowsSchema,
|
|
620
|
+
headerRow: t.Optional(PositiveInteger),
|
|
621
|
+
valueInputOption: t.Optional(valueInputOptionSchema),
|
|
622
|
+
handlingExtraData: t.Optional(handlingExtraDataSchema),
|
|
623
|
+
useAppend: t.Optional(t.Boolean()),
|
|
624
|
+
}, { additionalProperties: false }),
|
|
627
625
|
async execute(input, ctx) {
|
|
628
626
|
const p = (input ?? {});
|
|
629
627
|
const spreadsheetId = p.spreadsheetId;
|
|
@@ -684,39 +682,37 @@ export default function googleSheets(rl) {
|
|
|
684
682
|
});
|
|
685
683
|
// ── Update ────────────────────────────────────────────
|
|
686
684
|
rl.registerAction("sheet.update", {
|
|
685
|
+
access: "write",
|
|
687
686
|
description: "Update rows matched by a key column (or by the synthetic 'row_number' field). Rows are objects; undefined/null values are skipped.",
|
|
688
|
-
inputSchema: {
|
|
689
|
-
spreadsheetId:
|
|
690
|
-
sheet:
|
|
691
|
-
rows:
|
|
692
|
-
matchKey:
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
dataStartRow: { type: "number", required: false },
|
|
699
|
-
valueInputOption: { type: "string", required: false },
|
|
700
|
-
handlingExtraData: { type: "string", required: false },
|
|
701
|
-
},
|
|
687
|
+
inputSchema: t.Object({
|
|
688
|
+
spreadsheetId: Id,
|
|
689
|
+
sheet: sheetReferenceSchema,
|
|
690
|
+
rows: t.Array(objectRowSchema),
|
|
691
|
+
matchKey: NonEmptyString,
|
|
692
|
+
headerRow: t.Optional(PositiveInteger),
|
|
693
|
+
dataStartRow: t.Optional(PositiveInteger),
|
|
694
|
+
valueInputOption: t.Optional(valueInputOptionSchema),
|
|
695
|
+
handlingExtraData: t.Optional(handlingExtraDataSchema),
|
|
696
|
+
}, { additionalProperties: false }),
|
|
702
697
|
async execute(input, ctx) {
|
|
703
698
|
const p = (input ?? {});
|
|
704
699
|
return runUpdateOrUpsert(ctx, p, false);
|
|
705
700
|
},
|
|
706
701
|
});
|
|
707
702
|
rl.registerAction("sheet.appendOrUpdate", {
|
|
703
|
+
access: "write",
|
|
708
704
|
description: "Upsert rows. Rows whose match value is found are updated in place; rows with a missing or unknown match value are appended.",
|
|
709
|
-
inputSchema: {
|
|
710
|
-
spreadsheetId:
|
|
711
|
-
sheet:
|
|
712
|
-
rows:
|
|
713
|
-
matchKey:
|
|
714
|
-
headerRow:
|
|
715
|
-
dataStartRow:
|
|
716
|
-
valueInputOption:
|
|
717
|
-
handlingExtraData:
|
|
718
|
-
useAppend:
|
|
719
|
-
},
|
|
705
|
+
inputSchema: t.Object({
|
|
706
|
+
spreadsheetId: Id,
|
|
707
|
+
sheet: sheetReferenceSchema,
|
|
708
|
+
rows: t.Array(objectRowSchema),
|
|
709
|
+
matchKey: NonEmptyString,
|
|
710
|
+
headerRow: t.Optional(PositiveInteger),
|
|
711
|
+
dataStartRow: t.Optional(PositiveInteger),
|
|
712
|
+
valueInputOption: t.Optional(valueInputOptionSchema),
|
|
713
|
+
handlingExtraData: t.Optional(handlingExtraDataSchema),
|
|
714
|
+
useAppend: t.Optional(t.Boolean()),
|
|
715
|
+
}, { additionalProperties: false }),
|
|
720
716
|
async execute(input, ctx) {
|
|
721
717
|
const p = (input ?? {});
|
|
722
718
|
return runUpdateOrUpsert(ctx, p, true);
|
|
@@ -724,26 +720,72 @@ export default function googleSheets(rl) {
|
|
|
724
720
|
});
|
|
725
721
|
// ── Clear ─────────────────────────────────────────────
|
|
726
722
|
rl.registerAction("sheet.clear", {
|
|
723
|
+
access: "write",
|
|
727
724
|
description: "Clear values from a sheet. Modes: wholeSheet (optional keepFirstRow) | rows | columns | range.",
|
|
728
|
-
inputSchema: {
|
|
729
|
-
spreadsheetId:
|
|
730
|
-
sheet:
|
|
731
|
-
mode:
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
725
|
+
inputSchema: t.Object({
|
|
726
|
+
spreadsheetId: Id,
|
|
727
|
+
sheet: sheetReferenceSchema,
|
|
728
|
+
mode: t.Optional(stringEnum(["wholeSheet", "rows", "columns", "range"])),
|
|
729
|
+
startRow: t.Optional(PositiveInteger),
|
|
730
|
+
rowCount: t.Optional(PositiveInteger),
|
|
731
|
+
startColumn: t.Optional(t.String({ pattern: "^[A-Za-z]+$" })),
|
|
732
|
+
columnCount: t.Optional(PositiveInteger),
|
|
733
|
+
range: t.Optional(NonEmptyString),
|
|
734
|
+
keepFirstRow: t.Optional(t.Boolean()),
|
|
735
|
+
}, {
|
|
736
|
+
additionalProperties: false,
|
|
737
|
+
oneOf: [
|
|
738
|
+
{
|
|
739
|
+
properties: { mode: { const: "wholeSheet" } },
|
|
740
|
+
not: {
|
|
741
|
+
anyOf: [
|
|
742
|
+
{ required: ["startRow"] },
|
|
743
|
+
{ required: ["rowCount"] },
|
|
744
|
+
{ required: ["startColumn"] },
|
|
745
|
+
{ required: ["columnCount"] },
|
|
746
|
+
{ required: ["range"] },
|
|
747
|
+
],
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
properties: { mode: { const: "rows" } },
|
|
752
|
+
required: ["mode"],
|
|
753
|
+
not: {
|
|
754
|
+
anyOf: [
|
|
755
|
+
{ required: ["startColumn"] },
|
|
756
|
+
{ required: ["columnCount"] },
|
|
757
|
+
{ required: ["range"] },
|
|
758
|
+
{ required: ["keepFirstRow"] },
|
|
759
|
+
],
|
|
760
|
+
},
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
properties: { mode: { const: "columns" } },
|
|
764
|
+
required: ["mode"],
|
|
765
|
+
not: {
|
|
766
|
+
anyOf: [
|
|
767
|
+
{ required: ["startRow"] },
|
|
768
|
+
{ required: ["rowCount"] },
|
|
769
|
+
{ required: ["range"] },
|
|
770
|
+
{ required: ["keepFirstRow"] },
|
|
771
|
+
],
|
|
772
|
+
},
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
properties: { mode: { const: "range" } },
|
|
776
|
+
required: ["mode", "range"],
|
|
777
|
+
not: {
|
|
778
|
+
anyOf: [
|
|
779
|
+
{ required: ["startRow"] },
|
|
780
|
+
{ required: ["rowCount"] },
|
|
781
|
+
{ required: ["startColumn"] },
|
|
782
|
+
{ required: ["columnCount"] },
|
|
783
|
+
{ required: ["keepFirstRow"] },
|
|
784
|
+
],
|
|
785
|
+
},
|
|
786
|
+
},
|
|
787
|
+
],
|
|
788
|
+
}),
|
|
747
789
|
async execute(input, ctx) {
|
|
748
790
|
const p = (input ?? {});
|
|
749
791
|
const sheetName = typeof p.sheet === "number"
|
|
@@ -768,7 +810,9 @@ export default function googleSheets(rl) {
|
|
|
768
810
|
}
|
|
769
811
|
else if (mode === "range") {
|
|
770
812
|
const region = String(p.range ?? "");
|
|
771
|
-
range = region.includes("!")
|
|
813
|
+
range = region.includes("!")
|
|
814
|
+
? `${sheetName}!${region.split("!")[1]}`
|
|
815
|
+
: `${sheetName}!${region}`;
|
|
772
816
|
}
|
|
773
817
|
else {
|
|
774
818
|
range = sheetName;
|
|
@@ -786,18 +830,15 @@ export default function googleSheets(rl) {
|
|
|
786
830
|
});
|
|
787
831
|
// ── Delete rows/columns ───────────────────────────────
|
|
788
832
|
rl.registerAction("sheet.deleteDimension", {
|
|
833
|
+
access: "write",
|
|
789
834
|
description: "Delete a range of rows or columns",
|
|
790
|
-
inputSchema: {
|
|
791
|
-
spreadsheetId:
|
|
792
|
-
sheet:
|
|
793
|
-
dimension:
|
|
794
|
-
startIndex:
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
description: "1-indexed (row number) or column letter position",
|
|
798
|
-
},
|
|
799
|
-
count: { type: "number", required: false, description: "How many to delete (default: 1)" },
|
|
800
|
-
},
|
|
835
|
+
inputSchema: t.Object({
|
|
836
|
+
spreadsheetId: Id,
|
|
837
|
+
sheet: sheetReferenceSchema,
|
|
838
|
+
dimension: stringEnum(["ROWS", "COLUMNS"]),
|
|
839
|
+
startIndex: PositiveInteger,
|
|
840
|
+
count: t.Optional(PositiveInteger),
|
|
841
|
+
}, { additionalProperties: false }),
|
|
801
842
|
async execute(input, ctx) {
|
|
802
843
|
const p = (input ?? {});
|
|
803
844
|
const sheetId = await resolveSheetId(ctx, p.spreadsheetId, p.sheet);
|
|
@@ -820,114 +861,155 @@ export default function googleSheets(rl) {
|
|
|
820
861
|
});
|
|
821
862
|
// ── Raw batchUpdate ───────────────────────────────────
|
|
822
863
|
rl.registerAction("sheet.batchUpdate", {
|
|
864
|
+
access: "write",
|
|
823
865
|
description: "Raw passthrough to spreadsheets:batchUpdate for anything this plugin doesn't expose directly (formatting, merges, conditional rules, …).",
|
|
824
|
-
inputSchema: {
|
|
825
|
-
spreadsheetId:
|
|
826
|
-
requests: {
|
|
827
|
-
},
|
|
866
|
+
inputSchema: t.Object({
|
|
867
|
+
spreadsheetId: Id,
|
|
868
|
+
requests: t.Array(RawGoogleObject, { minItems: 1 }),
|
|
869
|
+
}, { additionalProperties: false }),
|
|
828
870
|
async execute(input, ctx) {
|
|
829
871
|
const p = (input ?? {});
|
|
830
872
|
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, p.requests);
|
|
831
873
|
},
|
|
832
874
|
});
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
return { updated: 0, appended: 0 };
|
|
847
|
-
}
|
|
848
|
-
const matchKey = p.matchKey;
|
|
849
|
-
if (!matchKey)
|
|
850
|
-
throw new Error("googleSheets: matchKey is required");
|
|
851
|
-
const valueInputOption = p.valueInputOption ?? "USER_ENTERED";
|
|
852
|
-
const allProps = await getSheetProperties(ctx, spreadsheetId);
|
|
853
|
-
const prop = allProps.find((s) => s.title === sheetIdOrName || String(s.sheetId) === String(sheetIdOrName));
|
|
854
|
-
if (!prop)
|
|
855
|
-
throw new Error(`googleSheets: sheet "${sheetIdOrName}" not found`);
|
|
856
|
-
const sheetName = prop.title;
|
|
857
|
-
const sheetId = prop.sheetId;
|
|
858
|
-
const headerRowIdx = Math.max(1, p.headerRow ?? 1) - 1;
|
|
859
|
-
const dataStartRowIdx = Math.max(headerRowIdx + 1, (p.dataStartRow ?? headerRowIdx + 2) - 1);
|
|
860
|
-
const handlingExtraData = p.handlingExtraData ?? "insertInNewColumn";
|
|
861
|
-
// Headers come from FORMATTED_VALUE (cosmetic strings). The match
|
|
862
|
-
// column needs UNFORMATTED_VALUE so "1,234" in input matches 1234
|
|
863
|
-
// on the sheet (issue a second fetch with UNFORMATTED_VALUE).
|
|
864
|
-
const sheetData = await getValues(ctx, spreadsheetId, sheetName, "FORMATTED_VALUE");
|
|
865
|
-
let headers = sheetData[headerRowIdx] ?? [];
|
|
866
|
-
let keyColumnValues = [];
|
|
867
|
-
if (matchKey !== ROW_NUMBER) {
|
|
868
|
-
const idx = headers.indexOf(matchKey);
|
|
869
|
-
if (idx === -1) {
|
|
870
|
-
if (!upsert)
|
|
871
|
-
throw new Error(`googleSheets: match column "${matchKey}" not found`);
|
|
875
|
+
/**
|
|
876
|
+
* Shared implementation for `sheet.update` and `sheet.appendOrUpdate`.
|
|
877
|
+
* Reads current headers + the key column, decides per row whether
|
|
878
|
+
* it's an update or an append, issues one `values:batchUpdate` for
|
|
879
|
+
* the updates, and (in upsert mode) falls through to the append
|
|
880
|
+
* path for the rest.
|
|
881
|
+
*/
|
|
882
|
+
async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
883
|
+
const spreadsheetId = p.spreadsheetId;
|
|
884
|
+
const sheetIdOrName = p.sheet;
|
|
885
|
+
const rows = p.rows;
|
|
886
|
+
if (!Array.isArray(rows) || rows.length === 0) {
|
|
887
|
+
return { updated: 0, appended: 0 };
|
|
872
888
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
889
|
+
const matchKey = p.matchKey;
|
|
890
|
+
if (!matchKey)
|
|
891
|
+
throw new Error("googleSheets: matchKey is required");
|
|
892
|
+
const valueInputOption = p.valueInputOption ?? "USER_ENTERED";
|
|
893
|
+
const allProps = await getSheetProperties(ctx, spreadsheetId);
|
|
894
|
+
const prop = allProps.find((s) => s.title === sheetIdOrName ||
|
|
895
|
+
String(s.sheetId) === String(sheetIdOrName));
|
|
896
|
+
if (!prop)
|
|
897
|
+
throw new Error(`googleSheets: sheet "${sheetIdOrName}" not found`);
|
|
898
|
+
const sheetName = prop.title;
|
|
899
|
+
const sheetId = prop.sheetId;
|
|
900
|
+
const headerRowIdx = Math.max(1, p.headerRow ?? 1) - 1;
|
|
901
|
+
const dataStartRowIdx = Math.max(headerRowIdx + 1, (p.dataStartRow ?? headerRowIdx + 2) - 1);
|
|
902
|
+
const handlingExtraData = p.handlingExtraData ??
|
|
903
|
+
"insertInNewColumn";
|
|
904
|
+
// Headers come from FORMATTED_VALUE (cosmetic strings). The match
|
|
905
|
+
// column needs UNFORMATTED_VALUE so "1,234" in input matches 1234
|
|
906
|
+
// on the sheet (issue a second fetch with UNFORMATTED_VALUE).
|
|
907
|
+
const sheetData = await getValues(ctx, spreadsheetId, sheetName, "FORMATTED_VALUE");
|
|
908
|
+
let headers = sheetData[headerRowIdx] ?? [];
|
|
909
|
+
let keyColumnValues = [];
|
|
910
|
+
if (matchKey !== ROW_NUMBER) {
|
|
911
|
+
const idx = headers.indexOf(matchKey);
|
|
912
|
+
if (idx === -1) {
|
|
913
|
+
if (!upsert)
|
|
914
|
+
throw new Error(`googleSheets: match column "${matchKey}" not found`);
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
const unformatted = await getValues(ctx, spreadsheetId, sheetName, "UNFORMATTED_VALUE");
|
|
918
|
+
keyColumnValues = unformatted
|
|
919
|
+
.slice(dataStartRowIdx)
|
|
920
|
+
.map((r) => String(r[idx] ?? ""));
|
|
921
|
+
}
|
|
876
922
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
}, { valueInputOption });
|
|
886
|
-
}
|
|
887
|
-
// Qualify update ranges with the sheet name (prepareUpdateOrUpsert
|
|
888
|
-
// returned bare A1 cells like "C5").
|
|
889
|
-
const updateData = prepared.updateData.map((d) => ({
|
|
890
|
-
range: `${sheetName}!${d.range}`,
|
|
891
|
-
values: d.values,
|
|
892
|
-
}));
|
|
893
|
-
if (updateData.length > 0) {
|
|
894
|
-
await batchValuesUpdate(ctx, spreadsheetId, updateData, valueInputOption);
|
|
895
|
-
}
|
|
896
|
-
if (upsert && prepared.appendData.length > 0) {
|
|
897
|
-
const values = objectsToRows(prepared.appendData, headers);
|
|
898
|
-
if (p.useAppend) {
|
|
899
|
-
await sheetsRequest(ctx, "POST", `/v4/spreadsheets/${spreadsheetId}/values/${encodeA1(sheetName)}:append`, { range: sheetName, values }, { valueInputOption, insertDataOption: "INSERT_ROWS" });
|
|
923
|
+
const prepared = prepareUpdateOrUpsert(rows, headers, keyColumnValues, dataStartRowIdx, matchKey, { upsert, handlingExtraData });
|
|
924
|
+
// If we added new columns, extend the header row on the sheet first.
|
|
925
|
+
if (prepared.newColumns.length > 0) {
|
|
926
|
+
headers = [...headers, ...prepared.newColumns];
|
|
927
|
+
await sheetsRequest(ctx, "PUT", `/v4/spreadsheets/${spreadsheetId}/values/${encodeA1(`${sheetName}!${headerRowIdx + 1}:${headerRowIdx + 1}`)}`, {
|
|
928
|
+
range: `${sheetName}!${headerRowIdx + 1}:${headerRowIdx + 1}`,
|
|
929
|
+
values: [headers],
|
|
930
|
+
}, { valueInputOption });
|
|
900
931
|
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
932
|
+
// Qualify update ranges with the sheet name (prepareUpdateOrUpsert
|
|
933
|
+
// returned bare A1 cells like "C5").
|
|
934
|
+
const updateData = prepared.updateData.map((d) => ({
|
|
935
|
+
range: `${sheetName}!${d.range}`,
|
|
936
|
+
values: d.values,
|
|
937
|
+
}));
|
|
938
|
+
if (updateData.length > 0) {
|
|
939
|
+
await batchValuesUpdate(ctx, spreadsheetId, updateData, valueInputOption);
|
|
906
940
|
}
|
|
941
|
+
if (upsert && prepared.appendData.length > 0) {
|
|
942
|
+
const values = objectsToRows(prepared.appendData, headers);
|
|
943
|
+
if (p.useAppend) {
|
|
944
|
+
await sheetsRequest(ctx, "POST", `/v4/spreadsheets/${spreadsheetId}/values/${encodeA1(sheetName)}:append`, { range: sheetName, values }, { valueInputOption, insertDataOption: "INSERT_ROWS" });
|
|
945
|
+
}
|
|
946
|
+
else {
|
|
947
|
+
const lastRow = sheetData.length;
|
|
948
|
+
await appendEmptyRow(ctx, spreadsheetId, sheetId);
|
|
949
|
+
const targetRange = `${sheetName}!${lastRow + 1}:${lastRow + values.length}`;
|
|
950
|
+
await sheetsRequest(ctx, "PUT", `/v4/spreadsheets/${spreadsheetId}/values/${encodeA1(targetRange)}`, { range: targetRange, values }, { valueInputOption });
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return {
|
|
954
|
+
updated: prepared.updateData.length,
|
|
955
|
+
appended: prepared.appendData.length,
|
|
956
|
+
newColumns: prepared.newColumns,
|
|
957
|
+
};
|
|
907
958
|
}
|
|
908
|
-
return {
|
|
909
|
-
updated: prepared.updateData.length,
|
|
910
|
-
appended: prepared.appendData.length,
|
|
911
|
-
newColumns: prepared.newColumns,
|
|
912
|
-
};
|
|
913
959
|
// ─── Charts ─────────────────────────────────────────────────────
|
|
914
960
|
rl.registerAction("chart.add", {
|
|
961
|
+
access: "write",
|
|
915
962
|
description: "Embed a chart on a sheet. Minimal signature: type ('COLUMN'|'BAR'|'LINE'|'AREA'|'PIE'|'SCATTER'|'COMBO'), data source (sheet name + A1 range), and target anchor cell. For full control pass a raw `chartSpec` object instead.",
|
|
916
|
-
inputSchema: {
|
|
917
|
-
spreadsheetId:
|
|
918
|
-
title:
|
|
919
|
-
type:
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
963
|
+
inputSchema: t.Object({
|
|
964
|
+
spreadsheetId: Id,
|
|
965
|
+
title: t.Optional(t.String()),
|
|
966
|
+
type: t.Optional(stringEnum([
|
|
967
|
+
"COLUMN",
|
|
968
|
+
"BAR",
|
|
969
|
+
"LINE",
|
|
970
|
+
"AREA",
|
|
971
|
+
"PIE",
|
|
972
|
+
"SCATTER",
|
|
973
|
+
"COMBO",
|
|
974
|
+
])),
|
|
975
|
+
sourceSheet: t.Optional(sheetReferenceSchema),
|
|
976
|
+
sourceRange: t.Optional(NonEmptyString),
|
|
977
|
+
legendPosition: t.Optional(stringEnum([
|
|
978
|
+
"BOTTOM_LEGEND",
|
|
979
|
+
"TOP_LEGEND",
|
|
980
|
+
"RIGHT_LEGEND",
|
|
981
|
+
"LEFT_LEGEND",
|
|
982
|
+
"NO_LEGEND",
|
|
983
|
+
])),
|
|
984
|
+
stackedType: t.Optional(stringEnum(["STACKED", "PERCENT_STACKED"])),
|
|
985
|
+
anchorSheet: sheetReferenceSchema,
|
|
986
|
+
anchorRow: t.Optional(NonNegativeInteger),
|
|
987
|
+
anchorColumn: t.Optional(NonNegativeInteger),
|
|
988
|
+
widthPx: t.Optional(PositiveInteger),
|
|
989
|
+
heightPx: t.Optional(PositiveInteger),
|
|
990
|
+
chartSpec: t.Optional(RawGoogleObject),
|
|
991
|
+
}, {
|
|
992
|
+
additionalProperties: false,
|
|
993
|
+
oneOf: [
|
|
994
|
+
{
|
|
995
|
+
required: ["chartSpec"],
|
|
996
|
+
not: {
|
|
997
|
+
anyOf: [
|
|
998
|
+
{ required: ["title"] },
|
|
999
|
+
{ required: ["type"] },
|
|
1000
|
+
{ required: ["sourceSheet"] },
|
|
1001
|
+
{ required: ["sourceRange"] },
|
|
1002
|
+
{ required: ["legendPosition"] },
|
|
1003
|
+
{ required: ["stackedType"] },
|
|
1004
|
+
],
|
|
1005
|
+
},
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
required: ["sourceSheet", "sourceRange"],
|
|
1009
|
+
not: { required: ["chartSpec"] },
|
|
1010
|
+
},
|
|
1011
|
+
],
|
|
1012
|
+
}),
|
|
931
1013
|
async execute(input, ctx) {
|
|
932
1014
|
const p = (input ?? {});
|
|
933
1015
|
const spreadsheetId = p.spreadsheetId;
|
|
@@ -946,14 +1028,41 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
946
1028
|
legendPosition: p.legendPosition ?? "BOTTOM_LEGEND",
|
|
947
1029
|
stackedType: p.stackedType,
|
|
948
1030
|
headerCount: 1,
|
|
949
|
-
domains: [
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1031
|
+
domains: [
|
|
1032
|
+
{
|
|
1033
|
+
domain: {
|
|
1034
|
+
sourceRange: {
|
|
1035
|
+
sources: [
|
|
1036
|
+
{
|
|
1037
|
+
sheetId: grid.sheetId,
|
|
1038
|
+
startRowIndex: grid.startRowIndex,
|
|
1039
|
+
endRowIndex: grid.endRowIndex,
|
|
1040
|
+
startColumnIndex: grid.startColumnIndex,
|
|
1041
|
+
endColumnIndex: grid.startColumnIndex + 1,
|
|
1042
|
+
},
|
|
1043
|
+
],
|
|
1044
|
+
},
|
|
1045
|
+
},
|
|
1046
|
+
},
|
|
1047
|
+
],
|
|
1048
|
+
series: [
|
|
1049
|
+
{
|
|
1050
|
+
series: {
|
|
1051
|
+
sourceRange: {
|
|
1052
|
+
sources: [
|
|
1053
|
+
{
|
|
1054
|
+
sheetId: grid.sheetId,
|
|
1055
|
+
startRowIndex: grid.startRowIndex,
|
|
1056
|
+
endRowIndex: grid.endRowIndex,
|
|
1057
|
+
startColumnIndex: grid.startColumnIndex + 1,
|
|
1058
|
+
endColumnIndex: grid.endColumnIndex,
|
|
1059
|
+
},
|
|
1060
|
+
],
|
|
1061
|
+
},
|
|
1062
|
+
},
|
|
1063
|
+
targetAxis: "LEFT_AXIS",
|
|
1064
|
+
},
|
|
1065
|
+
],
|
|
957
1066
|
},
|
|
958
1067
|
};
|
|
959
1068
|
}
|
|
@@ -963,7 +1072,11 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
963
1072
|
spec,
|
|
964
1073
|
position: {
|
|
965
1074
|
overlayPosition: {
|
|
966
|
-
anchorCell: {
|
|
1075
|
+
anchorCell: {
|
|
1076
|
+
sheetId: anchorSheetId,
|
|
1077
|
+
rowIndex: p.anchorRow ?? 0,
|
|
1078
|
+
columnIndex: p.anchorColumn ?? 0,
|
|
1079
|
+
},
|
|
967
1080
|
widthPixels: p.widthPx ?? 600,
|
|
968
1081
|
heightPixels: p.heightPx ?? 371,
|
|
969
1082
|
},
|
|
@@ -975,13 +1088,14 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
975
1088
|
},
|
|
976
1089
|
});
|
|
977
1090
|
rl.registerAction("chart.update", {
|
|
1091
|
+
access: "write",
|
|
978
1092
|
description: "Update an existing chart's spec by chartId.",
|
|
979
|
-
inputSchema: {
|
|
980
|
-
spreadsheetId:
|
|
981
|
-
chartId:
|
|
982
|
-
chartSpec:
|
|
983
|
-
fields:
|
|
984
|
-
},
|
|
1093
|
+
inputSchema: t.Object({
|
|
1094
|
+
spreadsheetId: Id,
|
|
1095
|
+
chartId: NonNegativeInteger,
|
|
1096
|
+
chartSpec: RawGoogleObject,
|
|
1097
|
+
fields: t.Optional(NonEmptyString),
|
|
1098
|
+
}, { additionalProperties: false }),
|
|
985
1099
|
async execute(input, ctx) {
|
|
986
1100
|
const p = (input ?? {});
|
|
987
1101
|
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, [
|
|
@@ -996,11 +1110,12 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
996
1110
|
},
|
|
997
1111
|
});
|
|
998
1112
|
rl.registerAction("chart.delete", {
|
|
1113
|
+
access: "write",
|
|
999
1114
|
description: "Delete a chart by its embedded-object id.",
|
|
1000
|
-
inputSchema: {
|
|
1001
|
-
spreadsheetId:
|
|
1002
|
-
chartId:
|
|
1003
|
-
},
|
|
1115
|
+
inputSchema: t.Object({
|
|
1116
|
+
spreadsheetId: Id,
|
|
1117
|
+
chartId: NonNegativeInteger,
|
|
1118
|
+
}, { additionalProperties: false }),
|
|
1004
1119
|
async execute(input, ctx) {
|
|
1005
1120
|
const p = (input ?? {});
|
|
1006
1121
|
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, [
|
|
@@ -1010,13 +1125,14 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1010
1125
|
});
|
|
1011
1126
|
// ─── Named ranges ───────────────────────────────────────────────
|
|
1012
1127
|
rl.registerAction("namedRange.add", {
|
|
1128
|
+
access: "write",
|
|
1013
1129
|
description: "Create a named range on a sheet (so formulas can reference it by name).",
|
|
1014
|
-
inputSchema: {
|
|
1015
|
-
spreadsheetId:
|
|
1016
|
-
name:
|
|
1017
|
-
sheet:
|
|
1018
|
-
range:
|
|
1019
|
-
},
|
|
1130
|
+
inputSchema: t.Object({
|
|
1131
|
+
spreadsheetId: Id,
|
|
1132
|
+
name: NonEmptyString,
|
|
1133
|
+
sheet: sheetReferenceSchema,
|
|
1134
|
+
range: NonEmptyString,
|
|
1135
|
+
}, { additionalProperties: false }),
|
|
1020
1136
|
async execute(input, ctx) {
|
|
1021
1137
|
const p = (input ?? {});
|
|
1022
1138
|
const sheetId = await resolveSheetId(ctx, p.spreadsheetId, p.sheet);
|
|
@@ -1027,11 +1143,12 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1027
1143
|
},
|
|
1028
1144
|
});
|
|
1029
1145
|
rl.registerAction("namedRange.delete", {
|
|
1146
|
+
access: "write",
|
|
1030
1147
|
description: "Delete a named range by its id.",
|
|
1031
|
-
inputSchema: {
|
|
1032
|
-
spreadsheetId:
|
|
1033
|
-
namedRangeId:
|
|
1034
|
-
},
|
|
1148
|
+
inputSchema: t.Object({
|
|
1149
|
+
spreadsheetId: Id,
|
|
1150
|
+
namedRangeId: Id,
|
|
1151
|
+
}, { additionalProperties: false }),
|
|
1035
1152
|
async execute(input, ctx) {
|
|
1036
1153
|
const p = (input ?? {});
|
|
1037
1154
|
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, [
|
|
@@ -1041,19 +1158,23 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1041
1158
|
});
|
|
1042
1159
|
// ─── Protected ranges ───────────────────────────────────────────
|
|
1043
1160
|
rl.registerAction("protectedRange.add", {
|
|
1161
|
+
access: "write",
|
|
1044
1162
|
description: "Protect a range from edits. Pass `editorEmails` to restrict who can still edit; without it, only the sheet owner can edit.",
|
|
1045
|
-
inputSchema: {
|
|
1046
|
-
spreadsheetId:
|
|
1047
|
-
sheet:
|
|
1048
|
-
range:
|
|
1049
|
-
description:
|
|
1050
|
-
warningOnly:
|
|
1051
|
-
editorEmails:
|
|
1052
|
-
},
|
|
1163
|
+
inputSchema: t.Object({
|
|
1164
|
+
spreadsheetId: Id,
|
|
1165
|
+
sheet: sheetReferenceSchema,
|
|
1166
|
+
range: t.Optional(NonEmptyString),
|
|
1167
|
+
description: t.Optional(t.String()),
|
|
1168
|
+
warningOnly: t.Optional(t.Boolean()),
|
|
1169
|
+
editorEmails: t.Optional(t.Array(NonEmptyString)),
|
|
1170
|
+
}, { additionalProperties: false }),
|
|
1053
1171
|
async execute(input, ctx) {
|
|
1054
1172
|
const p = (input ?? {});
|
|
1055
1173
|
const sheetId = await resolveSheetId(ctx, p.spreadsheetId, p.sheet);
|
|
1056
|
-
const protectedRange = {
|
|
1174
|
+
const protectedRange = {
|
|
1175
|
+
description: p.description,
|
|
1176
|
+
warningOnly: p.warningOnly,
|
|
1177
|
+
};
|
|
1057
1178
|
if (p.range)
|
|
1058
1179
|
protectedRange.range = a1RangeToGridRange(p.range, sheetId);
|
|
1059
1180
|
else
|
|
@@ -1067,11 +1188,12 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1067
1188
|
},
|
|
1068
1189
|
});
|
|
1069
1190
|
rl.registerAction("protectedRange.delete", {
|
|
1191
|
+
access: "write",
|
|
1070
1192
|
description: "Delete a protected range by its id.",
|
|
1071
|
-
inputSchema: {
|
|
1072
|
-
spreadsheetId:
|
|
1073
|
-
protectedRangeId:
|
|
1074
|
-
},
|
|
1193
|
+
inputSchema: t.Object({
|
|
1194
|
+
spreadsheetId: Id,
|
|
1195
|
+
protectedRangeId: NonNegativeInteger,
|
|
1196
|
+
}, { additionalProperties: false }),
|
|
1075
1197
|
async execute(input, ctx) {
|
|
1076
1198
|
const p = (input ?? {});
|
|
1077
1199
|
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, [
|
|
@@ -1081,22 +1203,39 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1081
1203
|
});
|
|
1082
1204
|
// ─── Conditional formatting ─────────────────────────────────────
|
|
1083
1205
|
rl.registerAction("conditionalFormat.add", {
|
|
1206
|
+
access: "write",
|
|
1084
1207
|
description: "Add a single-condition conditional-format rule. For complex rules pass a raw `rule` object instead of the simple builder.",
|
|
1085
|
-
inputSchema: {
|
|
1086
|
-
spreadsheetId:
|
|
1087
|
-
sheet:
|
|
1088
|
-
range:
|
|
1089
|
-
condition:
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1208
|
+
inputSchema: t.Object({
|
|
1209
|
+
spreadsheetId: Id,
|
|
1210
|
+
sheet: sheetReferenceSchema,
|
|
1211
|
+
range: NonEmptyString,
|
|
1212
|
+
condition: t.Optional(RawGoogleObject),
|
|
1213
|
+
backgroundColorHex: t.Optional(t.String({ pattern: "^#?[0-9a-fA-F]{6}$" })),
|
|
1214
|
+
foregroundColorHex: t.Optional(t.String({ pattern: "^#?[0-9a-fA-F]{6}$" })),
|
|
1215
|
+
bold: t.Optional(t.Boolean()),
|
|
1216
|
+
italic: t.Optional(t.Boolean()),
|
|
1217
|
+
rule: t.Optional(RawGoogleObject),
|
|
1218
|
+
}, {
|
|
1219
|
+
additionalProperties: false,
|
|
1220
|
+
oneOf: [
|
|
1221
|
+
{
|
|
1222
|
+
required: ["rule"],
|
|
1223
|
+
not: {
|
|
1224
|
+
anyOf: [
|
|
1225
|
+
{ required: ["condition"] },
|
|
1226
|
+
{ required: ["backgroundColorHex"] },
|
|
1227
|
+
{ required: ["foregroundColorHex"] },
|
|
1228
|
+
{ required: ["bold"] },
|
|
1229
|
+
{ required: ["italic"] },
|
|
1230
|
+
],
|
|
1231
|
+
},
|
|
1232
|
+
},
|
|
1233
|
+
{
|
|
1234
|
+
required: ["condition"],
|
|
1235
|
+
not: { required: ["rule"] },
|
|
1236
|
+
},
|
|
1237
|
+
],
|
|
1238
|
+
}),
|
|
1100
1239
|
async execute(input, ctx) {
|
|
1101
1240
|
const p = (input ?? {});
|
|
1102
1241
|
const sheetId = await resolveSheetId(ctx, p.spreadsheetId, p.sheet);
|
|
@@ -1118,18 +1257,24 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1118
1257
|
ts.italic = p.italic;
|
|
1119
1258
|
fmt.textFormat = ts;
|
|
1120
1259
|
}
|
|
1121
|
-
rule = {
|
|
1260
|
+
rule = {
|
|
1261
|
+
ranges: [grid],
|
|
1262
|
+
booleanRule: { condition: p.condition, format: fmt },
|
|
1263
|
+
};
|
|
1122
1264
|
}
|
|
1123
|
-
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, [
|
|
1265
|
+
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, [
|
|
1266
|
+
{ addConditionalFormatRule: { rule, index: 0 } },
|
|
1267
|
+
]);
|
|
1124
1268
|
},
|
|
1125
1269
|
});
|
|
1126
1270
|
rl.registerAction("conditionalFormat.delete", {
|
|
1271
|
+
access: "write",
|
|
1127
1272
|
description: "Delete a conditional-format rule by its index within the sheet's rule list.",
|
|
1128
|
-
inputSchema: {
|
|
1129
|
-
spreadsheetId:
|
|
1130
|
-
sheet:
|
|
1131
|
-
index:
|
|
1132
|
-
},
|
|
1273
|
+
inputSchema: t.Object({
|
|
1274
|
+
spreadsheetId: Id,
|
|
1275
|
+
sheet: sheetReferenceSchema,
|
|
1276
|
+
index: NonNegativeInteger,
|
|
1277
|
+
}, { additionalProperties: false }),
|
|
1133
1278
|
async execute(input, ctx) {
|
|
1134
1279
|
const p = (input ?? {});
|
|
1135
1280
|
const sheetId = await resolveSheetId(ctx, p.spreadsheetId, p.sheet);
|
|
@@ -1140,18 +1285,54 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1140
1285
|
});
|
|
1141
1286
|
// ─── Data validation ────────────────────────────────────────────
|
|
1142
1287
|
rl.registerAction("dataValidation.set", {
|
|
1288
|
+
access: "write",
|
|
1143
1289
|
description: "Apply a data-validation rule to a range. Pass either `condition` (BooleanCondition) or `oneOfList` (array of values for ONE_OF_LIST). Use `clear: true` to remove validation.",
|
|
1144
|
-
inputSchema: {
|
|
1145
|
-
spreadsheetId:
|
|
1146
|
-
sheet:
|
|
1147
|
-
range:
|
|
1148
|
-
condition:
|
|
1149
|
-
oneOfList: {
|
|
1150
|
-
showCustomUi:
|
|
1151
|
-
strict:
|
|
1152
|
-
inputMessage:
|
|
1153
|
-
clear:
|
|
1154
|
-
},
|
|
1290
|
+
inputSchema: t.Object({
|
|
1291
|
+
spreadsheetId: Id,
|
|
1292
|
+
sheet: sheetReferenceSchema,
|
|
1293
|
+
range: NonEmptyString,
|
|
1294
|
+
condition: t.Optional(RawGoogleObject),
|
|
1295
|
+
oneOfList: t.Optional(t.Array(JsonValue, { minItems: 1 })),
|
|
1296
|
+
showCustomUi: t.Optional(t.Boolean()),
|
|
1297
|
+
strict: t.Optional(t.Boolean()),
|
|
1298
|
+
inputMessage: t.Optional(t.String()),
|
|
1299
|
+
clear: t.Optional(t.Boolean()),
|
|
1300
|
+
}, {
|
|
1301
|
+
additionalProperties: false,
|
|
1302
|
+
oneOf: [
|
|
1303
|
+
{
|
|
1304
|
+
required: ["condition"],
|
|
1305
|
+
not: {
|
|
1306
|
+
anyOf: [
|
|
1307
|
+
{ required: ["oneOfList"] },
|
|
1308
|
+
{ required: ["clear"] },
|
|
1309
|
+
],
|
|
1310
|
+
},
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
required: ["oneOfList"],
|
|
1314
|
+
not: {
|
|
1315
|
+
anyOf: [
|
|
1316
|
+
{ required: ["condition"] },
|
|
1317
|
+
{ required: ["clear"] },
|
|
1318
|
+
],
|
|
1319
|
+
},
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
properties: { clear: { const: true } },
|
|
1323
|
+
required: ["clear"],
|
|
1324
|
+
not: {
|
|
1325
|
+
anyOf: [
|
|
1326
|
+
{ required: ["condition"] },
|
|
1327
|
+
{ required: ["oneOfList"] },
|
|
1328
|
+
{ required: ["showCustomUi"] },
|
|
1329
|
+
{ required: ["strict"] },
|
|
1330
|
+
{ required: ["inputMessage"] },
|
|
1331
|
+
],
|
|
1332
|
+
},
|
|
1333
|
+
},
|
|
1334
|
+
],
|
|
1335
|
+
}),
|
|
1155
1336
|
async execute(input, ctx) {
|
|
1156
1337
|
const p = (input ?? {});
|
|
1157
1338
|
const sheetId = await resolveSheetId(ctx, p.spreadsheetId, p.sheet);
|
|
@@ -1162,12 +1343,19 @@ async function runUpdateOrUpsert(ctx, p, upsert) {
|
|
|
1162
1343
|
if (!cond && Array.isArray(p.oneOfList)) {
|
|
1163
1344
|
cond = {
|
|
1164
1345
|
type: "ONE_OF_LIST",
|
|
1165
|
-
values: p.oneOfList.map((v) => ({
|
|
1346
|
+
values: p.oneOfList.map((v) => ({
|
|
1347
|
+
userEnteredValue: String(v),
|
|
1348
|
+
})),
|
|
1166
1349
|
};
|
|
1167
1350
|
}
|
|
1168
1351
|
if (!cond)
|
|
1169
1352
|
throw new Error("googleSheets.dataValidation.set: pass condition or oneOfList, or set clear=true");
|
|
1170
|
-
rule = {
|
|
1353
|
+
rule = {
|
|
1354
|
+
condition: cond,
|
|
1355
|
+
strict: p.strict ?? true,
|
|
1356
|
+
showCustomUi: p.showCustomUi ?? true,
|
|
1357
|
+
inputMessage: p.inputMessage,
|
|
1358
|
+
};
|
|
1171
1359
|
}
|
|
1172
1360
|
return spreadsheetBatchUpdate(ctx, p.spreadsheetId, [
|
|
1173
1361
|
{ setDataValidation: { range: grid, rule: rule ?? undefined } },
|