Skip to content

Commit e0e21ae

Browse files
committed
fix(plane): preserve expanded compatibility relations
1 parent 51c6963 commit e0e21ae

7 files changed

Lines changed: 245 additions & 24 deletions

File tree

‎apps/docs/content/docs/integrations/plane.mdx‎

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,7 +2229,14 @@ List cycles in Plane. Supports API v1 compatibility.
22292229
| ↳ `updated_by` | string | Updated by |
22302230
| ↳ `project` | string | Project |
22312231
| ↳ `workspace` | string | Workspace |
2232-
| ↳ `owned_by` | string | Owned by |
2232+
| ↳ `owned_by` | json | Owned by |
2233+
| ↳ `id` | string | Asset Id |
2234+
| ↳ `first_name` | string | Asset Id |
2235+
| ↳ `last_name` | string | Asset Id |
2236+
| ↳ `email` | string | Email |
2237+
| ↳ `avatar` | string | Asset Id |
2238+
| ↳ `avatar_url` | string | Avatar URL |
2239+
| ↳ `display_name` | string | Display name |
22332240
| ↳ `status` | string | Status |
22342241
| ↳ `deleted_by` | json | Deleted by |
22352242
| `detail` | string | Provider message when no records are returned. |
@@ -2274,7 +2281,7 @@ List labels in Plane. Supports API v1 compatibility.
22742281
| `count` | boolean | No | Defaults to `true`. Set to `false` to omit `total_count` and skip the count query. |
22752282
| `fields` | string | No | Comma-separated list of fields to return on each row. Unrequested keys are **omitted** from the response, not returned as `null`, so absent means "not requested" and `null` means "actually null". `id` always comes back whether or not you name it. Pass `all` for every requestable field. An unknown name is a `400` that lists the valid set and suggests the closest match, so a typo can't silently cost you the saving. Requestable here: `color`, `created_at`, `created_by_id`, `description`, `external_id`, `external_source`, `id`, `name`, `parent_id`, `sort_order`. See \[Sparse fields\]\(https://developers.plane.so/api-reference/v2/sparse-fields). |
22762283
| `cursor` | string | No | Cursor from next_cursor. Repeat the original filters, per_page, and order_by when following it. |
2277-
| `expand` | string | No | v1 compatibility only. Comma-separated list of related fields to expand in response Expanded relations appear beside their ID fields and survive sparse field filtering. Use only the relation names listed above. |
2284+
| `expand` | string | No | API v1 only. Comma-separated relations: `created_by`, `updated_by`, `workspace`, `project`, `parent`. Expansion replaces each relation ID with an object. Include the relation in `fields` when also requesting sparse fields. |
22782285
| `parent_id__isnull` | boolean | No | API v2: true selects top-level labels, false selects labels with a parent. |
22792286

22802287
#### Output
@@ -2311,11 +2318,40 @@ List labels in Plane. Supports API v1 compatibility.
23112318
| ↳ `sort_order` | number | Sort order |
23122319
| ↳ `external_source` | string | External source |
23132320
| ↳ `external_id` | string | External id |
2314-
| ↳ `created_by` | string | Created by |
2315-
| ↳ `updated_by` | string | Updated by |
2316-
| ↳ `workspace` | string | Workspace |
2317-
| ↳ `project` | string | Project |
2318-
| ↳ `parent` | string | Parent |
2321+
| ↳ `created_by` | json | Creator ID or expanded user. |
2322+
| ↳ `id` | string | Asset Id |
2323+
| ↳ `first_name` | string | Asset Id |
2324+
| ↳ `last_name` | string | Asset Id |
2325+
| ↳ `email` | string | Email |
2326+
| ↳ `avatar` | string | Asset Id |
2327+
| ↳ `avatar_url` | string | Avatar URL |
2328+
| ↳ `display_name` | string | Display name |
2329+
| ↳ `updated_by` | json | Updater ID or expanded user. |
2330+
| ↳ `id` | string | Asset Id |
2331+
| ↳ `first_name` | string | Asset Id |
2332+
| ↳ `last_name` | string | Asset Id |
2333+
| ↳ `email` | string | Email |
2334+
| ↳ `avatar` | string | Asset Id |
2335+
| ↳ `avatar_url` | string | Avatar URL |
2336+
| ↳ `display_name` | string | Display name |
2337+
| ↳ `workspace` | json | Workspace ID or expanded workspace. |
2338+
| ↳ `id` | string | Asset Id |
2339+
| ↳ `name` | string | Asset Id |
2340+
| ↳ `slug` | string | Slug |
2341+
| ↳ `project` | json | Project ID or expanded project. |
2342+
| ↳ `id` | string | Asset Id |
2343+
| ↳ `identifier` | string | Identifier |
2344+
| ↳ `name` | string | Asset Id |
2345+
| ↳ `cover_image` | string | Asset Id |
2346+
| ↳ `icon_prop` | json | Logo Props |
2347+
| ↳ `emoji` | string | Asset Id |
2348+
| ↳ `description` | string | Asset Id |
2349+
| ↳ `cover_image_url` | string | Asset Id |
2350+
| ↳ `archived_at` | string | Asset Id |
2351+
| ↳ `parent` | json | Parent ID or expanded parent reference. |
2352+
| ↳ `id` | string | Asset Id |
2353+
| ↳ `sequence_id` | number | Sequence ID |
2354+
| ↳ `project_id` | string | Asset Id |
23192355
| ↳ `deleted_by` | json | Deleted by |
23202356
| `detail` | string | Provider message when no records are returned. |
23212357
| `pagination` | object | Cursor pagination information. Bare-array responses have empty pagination. |
@@ -2600,14 +2636,22 @@ List project pages in Plane. Supports API v1 compatibility.
26002636
| ↳ `description` | json | Description |
26012637
| ↳ `created_at` | string | Created at |
26022638
| ↳ `updated_at` | string | Updated at |
2603-
| ↳ `owned_by` | string | Owned by |
2639+
| ↳ `owned_by` | json | Owned by |
2640+
| ↳ `id` | string | Asset Id |
2641+
| ↳ `first_name` | string | Asset Id |
2642+
| ↳ `last_name` | string | Asset Id |
2643+
| ↳ `email` | string | Email |
2644+
| ↳ `avatar` | string | Asset Id |
2645+
| ↳ `avatar_url` | string | Avatar URL |
2646+
| ↳ `display_name` | string | Display name |
26042647
| ↳ `anchor` | string | Anchor |
26052648
| ↳ `workspace` | string | Workspace |
26062649
| ↳ `projects` | array | Projects |
26072650
| ↳ `access` | json | Access |
26082651
| ↳ `is_locked` | boolean | Is locked |
26092652
| ↳ `archived_at` | string | Archived at |
26102653
| ↳ `parent_id` | string | Parent id |
2654+
| ↳ `parent` | json | Parent page ID or expanded page object in API v1. |
26112655
| ↳ `collection_id` | string | Collection id |
26122656
| ↳ `page_collection_id` | string | Page collection id |
26132657
| ↳ `color` | string | Color |

‎apps/sim/tools/generated/tool-metadata.ts‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎apps/sim/tools/generated/tool-outputs.ts‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { planeListLabelsTool } from '@/tools/plane/list_labels'
3+
import { planeListProjectPagesTool } from '@/tools/plane/list_project_pages'
4+
5+
const user = {
6+
id: 'user-id',
7+
first_name: 'Test',
8+
last_name: 'User',
9+
email: 'user@example.com',
10+
avatar: null,
11+
avatar_url: null,
12+
display_name: 'Test User',
13+
}
14+
15+
const relations = [
16+
{ field: 'created_by', expanded: user },
17+
{ field: 'updated_by', expanded: user },
18+
{ field: 'workspace', expanded: { id: 'workspace-id', name: 'Test', slug: 'test' } },
19+
{
20+
field: 'project',
21+
expanded: {
22+
id: 'project-id',
23+
identifier: 'TEST',
24+
name: 'Test project',
25+
cover_image: null,
26+
icon_prop: {},
27+
emoji: null,
28+
description: '',
29+
cover_image_url: null,
30+
archived_at: null,
31+
},
32+
},
33+
{ field: 'parent', expanded: { id: 'parent-id', project_id: 'project-id' } },
34+
]
35+
36+
const params = {
37+
apiKey: 'fixture-key',
38+
apiVersion: 'v1' as const,
39+
workspace_slug: 'test',
40+
project_id: 'project-id',
41+
}
42+
43+
describe('Plane compatibility relation projection', () => {
44+
it.each(relations)(
45+
'preserves expanded and scalar label $field values',
46+
async ({ field, expanded }) => {
47+
const rows = [
48+
{ id: 'expanded-label', name: 'Expanded', [field]: expanded },
49+
{ id: 'scalar-label', name: 'Scalar', [field]: expanded.id },
50+
{ id: 'null-label', name: 'Null', [field]: null },
51+
]
52+
const result = await planeListLabelsTool.transformResponse?.(
53+
Response.json({ results: rows, next_page_results: false }),
54+
params
55+
)
56+
expect(result?.output).toMatchObject({ results: rows })
57+
}
58+
)
59+
60+
it('preserves page parents, including nested provider content and scalar IDs', async () => {
61+
const parent = {
62+
id: 'parent-id',
63+
name: 'Parent',
64+
logo_props: { in_use: 'emoji', emoji: '1f4dd' },
65+
}
66+
const rows = [
67+
{ id: 'child-id', name: 'Child', parent_id: 'parent-id', parent },
68+
{ id: 'legacy-id', name: 'Legacy', parent: 'parent-id' },
69+
{ id: 'root-id', name: 'Root', parent: null },
70+
]
71+
const result = await planeListProjectPagesTool.transformResponse?.(
72+
Response.json({ results: rows, next_page_results: false }),
73+
params
74+
)
75+
expect(result?.output).toMatchObject({ results: rows })
76+
})
77+
78+
it('preserves expanded page owner details alongside nullable and scalar owners', async () => {
79+
const rows = [
80+
{ id: 'expanded-page', name: 'Expanded', owned_by: user },
81+
{ id: 'scalar-page', name: 'Scalar', owned_by: user.id },
82+
{ id: 'null-page', name: 'Null', owned_by: null },
83+
]
84+
const result = await planeListProjectPagesTool.transformResponse?.(
85+
Response.json({ results: rows, next_page_results: false }),
86+
params
87+
)
88+
expect(result?.output).toMatchObject({ results: rows })
89+
})
90+
})

‎apps/sim/tools/plane/list_labels.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export const planeListLabelsTool: ToolConfig<PlaneListLabelsParams, PlaneListLab
117117
required: false,
118118
visibility: 'user-or-llm',
119119
description:
120-
'v1 compatibility only. Comma-separated list of related fields to expand in response Expanded relations appear beside their ID fields and survive sparse field filtering. Use only the relation names listed above.',
120+
'API v1 only. Comma-separated relations: `created_by`, `updated_by`, `workspace`, `project`, `parent`. Expansion replaces each relation ID with an object. Include the relation in `fields` when also requesting sparse fields.',
121121
},
122122
parent_id__isnull: {
123123
type: 'boolean',

‎apps/sim/tools/plane/outputs.ts‎

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -898,10 +898,19 @@ const TYPEF949C2_OUTPUT: OutputProperty = {
898898
}
899899

900900
const OWNEDBY4BE915_OUTPUT: OutputProperty = {
901-
type: 'string',
902-
description: 'Asset Id',
901+
type: 'json',
902+
description: 'User ID or expanded user.',
903903
optional: true,
904904
nullable: true,
905+
properties: {
906+
id: ID_OUTPUT,
907+
first_name: FIRSTNAME_OUTPUT,
908+
last_name: LASTNAME_OUTPUT,
909+
email: { type: 'string', description: 'Email', optional: true, nullable: true },
910+
avatar: AVATAR_OUTPUT,
911+
avatar_url: AVATARURL_OUTPUT,
912+
display_name: { type: 'string', description: 'Display name', optional: true, nullable: true },
913+
},
905914
}
906915

907916
const ACCESS09C752_OUTPUT: OutputProperty = {
@@ -985,6 +994,12 @@ export const PLANEPAGECONTENT_OUTPUT: OutputProperty = {
985994
is_locked: { ...ISLOCKED_OUTPUT, description: 'Is locked' },
986995
archived_at: { ...ARCHIVEDAT_OUTPUT, description: 'Archived at' },
987996
parent_id: { ...PARENTID_OUTPUT, description: 'Parent id' },
997+
parent: {
998+
type: 'json',
999+
optional: true,
1000+
nullable: true,
1001+
description: 'Parent page ID or expanded page object in API v1.',
1002+
},
9881003
collection_id: { ...COLLECTIONID_OUTPUT, description: 'Collection id' },
9891004
page_collection_id: { ...PAGECOLLECTIONID_OUTPUT, description: 'Page collection id' },
9901005
color: { ...ASSETID_OUTPUT, description: 'Color' },
@@ -1048,11 +1063,47 @@ export const LABELB4435F_OUTPUT: OutputProperty = {
10481063
sort_order: { ...SORTORDER_OUTPUT, description: 'Sort order' },
10491064
external_source: { ...EXTERNALSOURCE_OUTPUT, description: 'External source' },
10501065
external_id: { ...EXTERNALID_OUTPUT, description: 'External id' },
1051-
created_by: { ...CREATEDBY94A812_OUTPUT, description: 'Created by' },
1052-
updated_by: { ...UPDATEDBY1F6D11_OUTPUT, description: 'Updated by' },
1053-
workspace: { ...WORKSPACE8D2899_OUTPUT, description: 'Workspace' },
1054-
project: { ...PROJECT0BF380_OUTPUT, description: 'Project' },
1055-
parent: { ...PARENT6F1635_OUTPUT, description: 'Parent' },
1066+
created_by: { ...OWNEDBY4BE915_OUTPUT, description: 'Creator ID or expanded user.' },
1067+
updated_by: { ...OWNEDBY4BE915_OUTPUT, description: 'Updater ID or expanded user.' },
1068+
workspace: {
1069+
type: 'json',
1070+
optional: true,
1071+
nullable: true,
1072+
description: 'Workspace ID or expanded workspace.',
1073+
properties: {
1074+
id: ID_OUTPUT,
1075+
name: NAME_OUTPUT,
1076+
slug: { ...ASSETID_OUTPUT, description: 'Slug' },
1077+
},
1078+
},
1079+
project: {
1080+
type: 'json',
1081+
optional: true,
1082+
nullable: true,
1083+
description: 'Project ID or expanded project.',
1084+
properties: {
1085+
id: ID_OUTPUT,
1086+
identifier: { ...ASSETID_OUTPUT, description: 'Identifier' },
1087+
name: NAME_OUTPUT,
1088+
cover_image: COVERIMAGE_OUTPUT,
1089+
icon_prop: ICONPROP_OUTPUT,
1090+
emoji: EMOJI_OUTPUT,
1091+
description: DESCRIPTION_OUTPUT,
1092+
cover_image_url: COVERIMAGEURL_OUTPUT,
1093+
archived_at: ARCHIVEDAT_OUTPUT,
1094+
},
1095+
},
1096+
parent: {
1097+
type: 'json',
1098+
optional: true,
1099+
nullable: true,
1100+
description: 'Parent ID or expanded parent reference.',
1101+
properties: {
1102+
id: ID_OUTPUT,
1103+
sequence_id: { type: 'number', description: 'Sequence ID', optional: true, nullable: true },
1104+
project_id: PROJECTID_OUTPUT,
1105+
},
1106+
},
10561107
deleted_by: { ...ID045D22_OUTPUT, description: 'Deleted by' },
10571108
},
10581109
}

‎apps/sim/tools/plane/schemas.ts‎

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ const type071f88Schema = z.object({
552552

553553
const typef949c2Schema = z.union([type071f88Schema, id045d22Schema])
554554

555-
const ownedBy4be915Schema = z.union([assetIdSchema, id045d22Schema])
555+
const ownedBy4be915Schema = z.union([assetIdSchema, userLiteSchema, id045d22Schema])
556556

557557
const access09c752Schema = z.union([access644595Schema, id045d22Schema, sortOrderdde3e5Schema])
558558

@@ -601,6 +601,7 @@ export const planePageContentSchema = z.object({
601601
is_locked: isLockedSchema.optional(),
602602
archived_at: archivedAtSchema.optional(),
603603
parent_id: parentIdSchema.optional(),
604+
parent: z.union([parentIdSchema, settings43c814Schema]).optional(),
604605
collection_id: collectionIdSchema.optional(),
605606
page_collection_id: pageCollectionIdSchema.optional(),
606607
color: assetIdSchema.optional(),
@@ -656,6 +657,41 @@ const labels3303c8Schema = z.array(labelsItema42358Schema)
656657

657658
const parent6f1635Schema = z.union([assetIdSchema, id045d22Schema])
658659

660+
const v1UserRelationSchema = z.union([createdBy94a812Schema, userLiteSchema])
661+
662+
const v1WorkspaceRelationSchema = z.union([
663+
workspace8d2899Schema,
664+
z.object({
665+
id: idSchema.optional(),
666+
name: nameSchema.optional(),
667+
slug: assetIdSchema.optional(),
668+
}),
669+
])
670+
671+
const v1ProjectRelationSchema = z.union([
672+
project0bf380Schema,
673+
z.object({
674+
id: idSchema.optional(),
675+
identifier: identifierSchema.optional(),
676+
name: nameSchema.optional(),
677+
cover_image: coverImageSchema.optional(),
678+
icon_prop: iconPropSchema.optional(),
679+
emoji: emojiSchema.optional(),
680+
description: descriptionSchema.optional(),
681+
cover_image_url: coverImageUrlSchema.optional(),
682+
archived_at: archivedAtSchema.optional(),
683+
}),
684+
])
685+
686+
const v1ParentRelationSchema = z.union([
687+
parent6f1635Schema,
688+
z.object({
689+
id: idSchema.optional(),
690+
sequence_id: sequenceIdSchema.optional(),
691+
project_id: projectIdSchema.optional(),
692+
}),
693+
])
694+
659695
export const labelb4435fSchema = z.object({
660696
id: idSchema.optional(),
661697
created_at: createdAtSchema.optional(),
@@ -667,11 +703,11 @@ export const labelb4435fSchema = z.object({
667703
sort_order: sortOrderSchema.optional(),
668704
external_source: externalSourceSchema.optional(),
669705
external_id: externalIdSchema.optional(),
670-
created_by: createdBy94a812Schema.optional(),
671-
updated_by: updatedBy1f6d11Schema.optional(),
672-
workspace: workspace8d2899Schema.optional(),
673-
project: project0bf380Schema.optional(),
674-
parent: parent6f1635Schema.optional(),
706+
created_by: v1UserRelationSchema.optional(),
707+
updated_by: v1UserRelationSchema.optional(),
708+
workspace: v1WorkspaceRelationSchema.optional(),
709+
project: v1ProjectRelationSchema.optional(),
710+
parent: v1ParentRelationSchema.optional(),
675711
deleted_by: id045d22Schema.optional(),
676712
})
677713

0 commit comments

Comments
 (0)