Skip to content

Commit bfae758

Browse files
mguptahubPlane AI
andauthored
feat: add workspace-level API resources [INFRA-396] (#46)
Mirrors the workspace-level resources from INFRA-394 (Python SDK) into the Node SDK. Adds 7 resource groups, all registered on PlaneClient and exported from the package index. New resources: - WorkspaceTemplates — workspace work item, project, and page templates (list, create, update, del) - WorkspaceWorkItemTypes — list, create, update + properties sub-resource (list, create, del) - WorkspaceWorkItemProperties — list, create, update, del + options sub-resource (list, create, update) - WorkspaceProjectLabels — list, create, update, del - WorkspaceProjectStates — list, create, update, del - WorkItemRelationDefinitions — list (?is_default, ?is_active), create, update, del - Releases — list, create, update + tags, labels, itemLabels sub-resources New models: - WorkspaceTemplate.ts (WorkspaceWorkItemTemplate, WorkspaceProjectTemplate, WorkspacePageTemplate) - WorkspaceProjectLabel.ts, WorkspaceProjectState.ts - WorkItemRelationDefinition.ts - Release.ts (Release, ReleaseTag, ReleaseLabel, AddReleaseItemLabel) - WorkspaceWorkItemTypePropertyLink added to WorkItemType.ts Unit tests added for all resources. README updated. Co-authored-by: Plane AI <noreply@plane.so>
1 parent 41eb144 commit bfae758

31 files changed

Lines changed: 1236 additions & 0 deletions

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ const project = await client.projects.create("workspace-slug", {
7676
- **Teamspaces**: Teamspace management
7777
- **Milestones**: Milestone tracking and management
7878
- **Initiatives**: Initiative management
79+
- **WorkspaceTemplates**: Workspace-level work item, project, and page templates
80+
- **WorkspaceWorkItemTypes**: Workspace-level work item type management with property links
81+
- **WorkspaceWorkItemProperties**: Workspace-level custom property management with options
82+
- **WorkspaceProjectLabels**: Workspace-level project label management
83+
- **WorkspaceProjectStates**: Workspace-level project state management
84+
- **WorkItemRelationDefinitions**: Custom work item relation type definitions
85+
- **Releases**: Release management with tags, labels, and item label assignment
7986
- **AgentRuns**: AI agent run orchestration and activity tracking
8087
- **Workflows**: Project workflow management with state attachments and transitions
8188
- **ProjectTemplates**: Work item and page template management per project

src/api/Releases/ItemLabels.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { BaseResource } from "../BaseResource";
2+
import { Configuration } from "../../Configuration";
3+
import { AddReleaseItemLabel, ReleaseLabel } from "../../models/Release";
4+
5+
/**
6+
* ReleaseItemLabels sub-resource
7+
* Manages labels assigned to a specific release
8+
*/
9+
export class ItemLabels extends BaseResource {
10+
constructor(config: Configuration) {
11+
super(config);
12+
}
13+
14+
async list(workspaceSlug: string, releaseId: string): Promise<ReleaseLabel[]> {
15+
const data = await this.get<ReleaseLabel[] | { results: ReleaseLabel[] }>(
16+
`/workspaces/${workspaceSlug}/releases/${releaseId}/labels/`
17+
);
18+
return Array.isArray(data) ? data : data.results;
19+
}
20+
21+
async create(workspaceSlug: string, releaseId: string, data: AddReleaseItemLabel): Promise<ReleaseLabel[]> {
22+
const result = await this.post<ReleaseLabel[] | { results: ReleaseLabel[] }>(
23+
`/workspaces/${workspaceSlug}/releases/${releaseId}/labels/`,
24+
data
25+
);
26+
return Array.isArray(result) ? result : result.results;
27+
}
28+
29+
async del(workspaceSlug: string, releaseId: string, labelId: string): Promise<void> {
30+
return this.httpDelete(`/workspaces/${workspaceSlug}/releases/${releaseId}/labels/${labelId}/`);
31+
}
32+
}

src/api/Releases/Labels.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { BaseResource } from "../BaseResource";
2+
import { Configuration } from "../../Configuration";
3+
import { CreateReleaseLabel, ReleaseLabel } from "../../models/Release";
4+
5+
/**
6+
* ReleaseLabels sub-resource
7+
* Manages release labels at the workspace level
8+
*/
9+
export class Labels extends BaseResource {
10+
constructor(config: Configuration) {
11+
super(config);
12+
}
13+
14+
async list(workspaceSlug: string): Promise<ReleaseLabel[]> {
15+
const data = await this.get<ReleaseLabel[] | { results: ReleaseLabel[] }>(
16+
`/workspaces/${workspaceSlug}/releases/labels/`
17+
);
18+
return Array.isArray(data) ? data : data.results;
19+
}
20+
21+
async create(workspaceSlug: string, data: CreateReleaseLabel): Promise<ReleaseLabel> {
22+
return this.post<ReleaseLabel>(`/workspaces/${workspaceSlug}/releases/labels/`, data);
23+
}
24+
}

src/api/Releases/Tags.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { BaseResource } from "../BaseResource";
2+
import { Configuration } from "../../Configuration";
3+
import { CreateReleaseTag, ReleaseTag } from "../../models/Release";
4+
5+
/**
6+
* ReleaseTags sub-resource
7+
* Manages release tags at the workspace level
8+
*/
9+
export class Tags extends BaseResource {
10+
constructor(config: Configuration) {
11+
super(config);
12+
}
13+
14+
async list(workspaceSlug: string): Promise<ReleaseTag[]> {
15+
const data = await this.get<ReleaseTag[] | { results: ReleaseTag[] }>(
16+
`/workspaces/${workspaceSlug}/releases/tags/`
17+
);
18+
return Array.isArray(data) ? data : data.results;
19+
}
20+
21+
async create(workspaceSlug: string, data: CreateReleaseTag): Promise<ReleaseTag> {
22+
return this.post<ReleaseTag>(`/workspaces/${workspaceSlug}/releases/tags/`, data);
23+
}
24+
}

src/api/Releases/index.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { BaseResource } from "../BaseResource";
2+
import { Configuration } from "../../Configuration";
3+
import { CreateRelease, Release, UpdateRelease } from "../../models/Release";
4+
import { Tags } from "./Tags";
5+
import { Labels } from "./Labels";
6+
import { ItemLabels } from "./ItemLabels";
7+
8+
/**
9+
* Releases API resource
10+
* Manages releases at the workspace level with tags, labels, and item-label sub-resources
11+
*/
12+
export class Releases extends BaseResource {
13+
public tags: Tags;
14+
public labels: Labels;
15+
public itemLabels: ItemLabels;
16+
17+
constructor(config: Configuration) {
18+
super(config);
19+
this.tags = new Tags(config);
20+
this.labels = new Labels(config);
21+
this.itemLabels = new ItemLabels(config);
22+
}
23+
24+
async list(workspaceSlug: string): Promise<Release[]> {
25+
const data = await this.get<Release[] | { results: Release[] }>(`/workspaces/${workspaceSlug}/releases/`);
26+
return Array.isArray(data) ? data : data.results;
27+
}
28+
29+
async create(workspaceSlug: string, data: CreateRelease): Promise<Release> {
30+
return this.post<Release>(`/workspaces/${workspaceSlug}/releases/`, data);
31+
}
32+
33+
async update(workspaceSlug: string, releaseId: string, data: UpdateRelease): Promise<Release> {
34+
return this.patch<Release>(`/workspaces/${workspaceSlug}/releases/${releaseId}/`, data);
35+
}
36+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { BaseResource } from "./BaseResource";
2+
import { Configuration } from "../Configuration";
3+
import {
4+
CreateWorkItemRelationDefinition,
5+
ListWorkItemRelationDefinitionsParams,
6+
UpdateWorkItemRelationDefinition,
7+
WorkItemRelationDefinition,
8+
} from "../models/WorkItemRelationDefinition";
9+
10+
/**
11+
* WorkItemRelationDefinitions API resource
12+
* Manages work item relation definitions at the workspace level
13+
*/
14+
export class WorkItemRelationDefinitions extends BaseResource {
15+
constructor(config: Configuration) {
16+
super(config);
17+
}
18+
19+
async list(
20+
workspaceSlug: string,
21+
params?: ListWorkItemRelationDefinitionsParams
22+
): Promise<WorkItemRelationDefinition[]> {
23+
const query: Record<string, string> = {};
24+
if (params?.is_default !== undefined) query["is_default"] = String(params.is_default);
25+
if (params?.is_active !== undefined) query["is_active"] = String(params.is_active);
26+
27+
const data = await this.get<WorkItemRelationDefinition[] | { results: WorkItemRelationDefinition[] }>(
28+
`/workspaces/${workspaceSlug}/work-item-relation-definitions/`,
29+
Object.keys(query).length ? query : undefined
30+
);
31+
return Array.isArray(data) ? data : data.results;
32+
}
33+
34+
async create(workspaceSlug: string, data: CreateWorkItemRelationDefinition): Promise<WorkItemRelationDefinition> {
35+
return this.post<WorkItemRelationDefinition>(`/workspaces/${workspaceSlug}/work-item-relation-definitions/`, data);
36+
}
37+
38+
async update(
39+
workspaceSlug: string,
40+
definitionId: string,
41+
data: UpdateWorkItemRelationDefinition
42+
): Promise<WorkItemRelationDefinition> {
43+
return this.patch<WorkItemRelationDefinition>(
44+
`/workspaces/${workspaceSlug}/work-item-relation-definitions/${definitionId}/`,
45+
data
46+
);
47+
}
48+
49+
async del(workspaceSlug: string, definitionId: string): Promise<void> {
50+
return this.httpDelete(`/workspaces/${workspaceSlug}/work-item-relation-definitions/${definitionId}/`);
51+
}
52+
}

src/api/WorkspaceProjectLabels.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { BaseResource } from "./BaseResource";
2+
import { Configuration } from "../Configuration";
3+
import {
4+
CreateWorkspaceProjectLabel,
5+
UpdateWorkspaceProjectLabel,
6+
WorkspaceProjectLabel,
7+
} from "../models/WorkspaceProjectLabel";
8+
9+
/**
10+
* WorkspaceProjectLabels API resource
11+
* Manages project labels at the workspace level
12+
*/
13+
export class WorkspaceProjectLabels extends BaseResource {
14+
constructor(config: Configuration) {
15+
super(config);
16+
}
17+
18+
async list(workspaceSlug: string): Promise<WorkspaceProjectLabel[]> {
19+
const data = await this.get<WorkspaceProjectLabel[] | { results: WorkspaceProjectLabel[] }>(
20+
`/workspaces/${workspaceSlug}/project-labels/`
21+
);
22+
return Array.isArray(data) ? data : data.results;
23+
}
24+
25+
async create(workspaceSlug: string, data: CreateWorkspaceProjectLabel): Promise<WorkspaceProjectLabel> {
26+
return this.post<WorkspaceProjectLabel>(`/workspaces/${workspaceSlug}/project-labels/`, data);
27+
}
28+
29+
async update(
30+
workspaceSlug: string,
31+
labelId: string,
32+
data: UpdateWorkspaceProjectLabel
33+
): Promise<WorkspaceProjectLabel> {
34+
return this.patch<WorkspaceProjectLabel>(`/workspaces/${workspaceSlug}/project-labels/${labelId}/`, data);
35+
}
36+
37+
async del(workspaceSlug: string, labelId: string): Promise<void> {
38+
return this.httpDelete(`/workspaces/${workspaceSlug}/project-labels/${labelId}/`);
39+
}
40+
}

src/api/WorkspaceProjectStates.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { BaseResource } from "./BaseResource";
2+
import { Configuration } from "../Configuration";
3+
import {
4+
CreateWorkspaceProjectState,
5+
UpdateWorkspaceProjectState,
6+
WorkspaceProjectState,
7+
} from "../models/WorkspaceProjectState";
8+
9+
/**
10+
* WorkspaceProjectStates API resource
11+
* Manages project states at the workspace level
12+
*/
13+
export class WorkspaceProjectStates extends BaseResource {
14+
constructor(config: Configuration) {
15+
super(config);
16+
}
17+
18+
async list(workspaceSlug: string): Promise<WorkspaceProjectState[]> {
19+
const data = await this.get<WorkspaceProjectState[] | { results: WorkspaceProjectState[] }>(
20+
`/workspaces/${workspaceSlug}/project-states/`
21+
);
22+
return Array.isArray(data) ? data : data.results;
23+
}
24+
25+
async create(workspaceSlug: string, data: CreateWorkspaceProjectState): Promise<WorkspaceProjectState> {
26+
return this.post<WorkspaceProjectState>(`/workspaces/${workspaceSlug}/project-states/`, data);
27+
}
28+
29+
async update(
30+
workspaceSlug: string,
31+
stateId: string,
32+
data: UpdateWorkspaceProjectState
33+
): Promise<WorkspaceProjectState> {
34+
return this.patch<WorkspaceProjectState>(`/workspaces/${workspaceSlug}/project-states/${stateId}/`, data);
35+
}
36+
37+
async del(workspaceSlug: string, stateId: string): Promise<void> {
38+
return this.httpDelete(`/workspaces/${workspaceSlug}/project-states/${stateId}/`);
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { BaseResource } from "../BaseResource";
2+
import { Configuration } from "../../Configuration";
3+
import {
4+
CreateWorkspacePageTemplate,
5+
UpdateWorkspacePageTemplate,
6+
WorkspacePageTemplate,
7+
} from "../../models/WorkspaceTemplate";
8+
9+
/**
10+
* WorkspacePageTemplates sub-resource
11+
* Manages page templates at the workspace level
12+
*/
13+
export class Pages extends BaseResource {
14+
constructor(config: Configuration) {
15+
super(config);
16+
}
17+
18+
async list(workspaceSlug: string): Promise<WorkspacePageTemplate[]> {
19+
const data = await this.get<WorkspacePageTemplate[] | { results: WorkspacePageTemplate[] }>(
20+
`/workspaces/${workspaceSlug}/pages/templates/`
21+
);
22+
return Array.isArray(data) ? data : data.results;
23+
}
24+
25+
async create(workspaceSlug: string, data: CreateWorkspacePageTemplate): Promise<WorkspacePageTemplate> {
26+
return this.post<WorkspacePageTemplate>(`/workspaces/${workspaceSlug}/pages/templates/`, data);
27+
}
28+
29+
async update(
30+
workspaceSlug: string,
31+
templateId: string,
32+
data: UpdateWorkspacePageTemplate
33+
): Promise<WorkspacePageTemplate> {
34+
return this.patch<WorkspacePageTemplate>(`/workspaces/${workspaceSlug}/pages/templates/${templateId}/`, data);
35+
}
36+
37+
async del(workspaceSlug: string, templateId: string): Promise<void> {
38+
return this.httpDelete(`/workspaces/${workspaceSlug}/pages/templates/${templateId}/`);
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { BaseResource } from "../BaseResource";
2+
import { Configuration } from "../../Configuration";
3+
import {
4+
CreateWorkspaceProjectTemplate,
5+
UpdateWorkspaceProjectTemplate,
6+
WorkspaceProjectTemplate,
7+
} from "../../models/WorkspaceTemplate";
8+
9+
/**
10+
* WorkspaceProjectTemplates sub-resource
11+
* Manages project templates at the workspace level
12+
*/
13+
export class Projects extends BaseResource {
14+
constructor(config: Configuration) {
15+
super(config);
16+
}
17+
18+
async list(workspaceSlug: string): Promise<WorkspaceProjectTemplate[]> {
19+
const data = await this.get<WorkspaceProjectTemplate[] | { results: WorkspaceProjectTemplate[] }>(
20+
`/workspaces/${workspaceSlug}/projects/templates/`
21+
);
22+
return Array.isArray(data) ? data : data.results;
23+
}
24+
25+
async create(workspaceSlug: string, data: CreateWorkspaceProjectTemplate): Promise<WorkspaceProjectTemplate> {
26+
return this.post<WorkspaceProjectTemplate>(`/workspaces/${workspaceSlug}/projects/templates/`, data);
27+
}
28+
29+
async update(
30+
workspaceSlug: string,
31+
templateId: string,
32+
data: UpdateWorkspaceProjectTemplate
33+
): Promise<WorkspaceProjectTemplate> {
34+
return this.patch<WorkspaceProjectTemplate>(`/workspaces/${workspaceSlug}/projects/templates/${templateId}/`, data);
35+
}
36+
37+
async del(workspaceSlug: string, templateId: string): Promise<void> {
38+
return this.httpDelete(`/workspaces/${workspaceSlug}/projects/templates/${templateId}/`);
39+
}
40+
}

0 commit comments

Comments
 (0)