Skip to content

feat: add workspace governance resources (states, workflows, type governance) + workflow parity - #54

Open
akhil-vamshi-konam wants to merge 1 commit into
mainfrom
feat-workspace-governance
Open

feat: add workspace governance resources (states, workflows, type governance) + workflow parity#54
akhil-vamshi-konam wants to merge 1 commit into
mainfrom
feat-workspace-governance

Conversation

@akhil-vamshi-konam

@akhil-vamshi-konam akhil-vamshi-konam commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds workspace governance support.

New resources

  • client.workspaceStates — workspace-level (catalog) work-item states. Dual-mode reads (catalog under governance, cross-project aggregate otherwise); writes require the workspace to own states/workflows.
  • client.workspaceWorkflows — the workspace workflow catalog, with .states (chain), .transitions, and .hooks sub-resources; usage report and activity log.
  • client.workItemTypeGovernance — governs which workflows a workspace-level work item type may use (any/constrained/required), with .pins (per-project overrides) and .projectWorkflows (project-side resolution, pick, fallback preview).

Workflows housekeeping parity

client.workflows (project-scoped) was missing several methods present in the public API: retrieve, delete, activities, submitWorkItemApproval, states.list/update/transfer, transitions.retrieve, and a new .hooks sub-resource.

Model changes

WorkspaceFeatures gains states_owned_by_workspace (read-only governance flag), work_item_types, and releases; fields are now optional to match partial-PATCH semantics.

Tests

  • Added coverage for all three new resources (workspace-states, workspace-workflows, work-item-type-governance) plus the Workflows housekeeping additions.
  • Hardened the existing project-scoped fixture setup (states, workflows, work item types, templates, properties) with a shared workspaceManagedReason helper: when a workspace/project-level feature conflicts with its workspace-governed equivalent (project-scoped writes correctly rejected 400 workspace_managed), the affected tests now log a clear skip warning and short-circuit instead of failing loud.

Workspace Governance tests
image
image
image

Project-level tests: skipped with warning, not failed.
image

Summary by CodeRabbit

  • New Features
    • Added workspace-level states and workflows with full lifecycle management, usage reporting, activities, transitions, and hooks.
    • Added work-item type governance tools for settings, workflow pins, project workflow selections, and change previews.
    • Added workflow approvals, transition retrieval, state transfers, and activity filtering.
    • Added workspace-managed resources to the client and public exports.
  • Documentation
    • Expanded API resource documentation to cover workflows and newly available workspace and governance resources.
  • Tests
    • Added coverage for workspace states, workspace workflows, governance, and workflow operations.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The SDK adds workspace state and workflow resources, work-item type governance APIs, workflow hooks and activity operations, typed models, client wiring, exports, documentation, and integration tests for workspace-managed behavior.

Changes

Workspace workflow and governance APIs

Layer / File(s) Summary
Models and public client wiring
README.md, src/models/*, src/client/plane-client.ts, src/index.ts
Adds typed models for workspace states, workflows, hooks, activities, approvals, and governance. Exposes the new resources through PlaneClient and package exports.
Workspace state and workflow resources
src/api/WorkspaceStates.ts, src/api/WorkspaceWorkflows/*, tests/unit/workspace-states.test.ts, tests/unit/workspace-workflows/*
Adds workspace state CRUD and workspace workflow operations for states, transitions, hooks, usage, activities, and cleanup.
Work-item type governance resources
src/api/WorkItemTypeGovernance/*, tests/unit/work-item-type-governance/*
Adds governance retrieval, updates, previews, pins, project workflow picks, and fallback previews.
Project workflow extensions
src/api/Workflows/*, tests/unit/workflows/*
Adds workflow retrieval and deletion, state membership operations, transition retrieval, hooks, activities, and approval submission.
Governance-aware test handling
tests/helpers/governance.ts, tests/unit/project-templates.test.ts, tests/unit/state.test.ts, tests/unit/work-item-types/*
Classifies workspace-managed API errors and skips project-scoped tests when workspace governance controls the resource.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant WorkspaceWorkflows
  participant WorkflowStates
  participant WorkflowTransitions
  participant WorkflowHooks
  Client->>WorkspaceWorkflows: create or retrieve workspace workflow
  WorkspaceWorkflows->>WorkflowStates: configure workflow states
  WorkspaceWorkflows->>WorkflowTransitions: configure state transitions
  WorkspaceWorkflows->>WorkflowHooks: manage transition hooks
  WorkspaceWorkflows-->>Client: return workflow activity and usage
Loading

Possibly related PRs

Suggested reviewers: prashant-surya

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: workspace governance resources and expanded workflow support.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-workspace-governance

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (6)
tests/unit/workspace-workflows/workspace-workflow.test.ts (2)

86-88: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for transition and hook writes.

The suite lists transitions but never calls transitions.create, transitions.update, or any hooks method. Those endpoints are new in this PR and stay untested. A create-then-delete transition step, plus one hook create, would cover the new paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/workspace-workflows/workspace-workflow.test.ts` around lines 86 -
88, Add coverage in the workspace workflow test around the existing transitions
listing: create a transition, update it, then delete it, and add one hook
creation using the workflow’s hooks API. Assert each operation succeeds and
retain the existing transitions list assertion, using the returned transition
and workflow identifiers for subsequent calls.

48-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Report the ungoverned case as skipped, not passed.

The early return makes this test pass with zero assertions in an ungoverned workspace. A configuration mistake then looks like a green run. The repo already exposes conditional helpers in tests/helpers/conditional-tests. governed is resolved in beforeAll, so a runtime skip is needed rather than a declaration-time guard.

♻️ Proposed skip
   it("should create a workflow, configure a chain, and clean up", async () => {
-    if (!governed) return;
+    if (!governed) {
+      console.warn("Workspace is not governed; skipping governed-write assertions.");
+      return;
+    }

If tests/helpers/conditional-tests exports an itIf helper, prefer it so Jest reports the test as skipped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/workspace-workflows/workspace-workflow.test.ts` around lines 48 -
49, Update the “should create a workflow, configure a chain, and clean up” test
to report ungoverned workspaces as skipped rather than passing with zero
assertions. Reuse the conditional helper from tests/helpers/conditional-tests,
selecting an approach that evaluates the beforeAll-resolved governed value at
runtime and preserves the existing test body for governed workspaces.
src/models/WorkspaceWorkflow.ts (2)

54-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the Create/Update DTOs from WorkspaceWorkflow.

CreateWorkspaceWorkflow and UpdateWorkspaceWorkflow redeclare fields that already exist on WorkspaceWorkflow. A rename on the entity will not propagate to these DTOs. The same pattern applies to CreateWorkspaceWorkflowTransition and UpdateWorkspaceWorkflowTransition at lines 141-157, where only state_id has no entity counterpart. src/models/Workflow.ts already uses the derived form.

♻️ Proposed derivation with `Pick` and `Partial`
-export type CreateWorkspaceWorkflow = {
-  name: string;
-  description?: string;
-};
+export type CreateWorkspaceWorkflow = Pick<WorkspaceWorkflow, "name"> &
+  Partial<Pick<WorkspaceWorkflow, "description">>;
 
 /**
  * Request model for updating workspace workflow metadata
  */
-export type UpdateWorkspaceWorkflow = Partial<{
-  name: string;
-  description: string;
-  is_active: boolean;
-}>;
+export type UpdateWorkspaceWorkflow = Partial<Pick<WorkspaceWorkflow, "name" | "description" | "is_active">>;

Apply the same change to the transition DTOs:

export type CreateWorkspaceWorkflowTransition = { state_id: string } & Pick<
  WorkspaceWorkflowTransition,
  "transition_state_id"
> &
  Partial<Pick<WorkspaceWorkflowTransition, "rejection_state_id" | "required_approvals" | "member_ids">>;

export type UpdateWorkspaceWorkflowTransition = Partial<
  Pick<WorkspaceWorkflowTransition, "transition_state_id" | "rejection_state_id" | "required_approvals" | "member_ids">
>;

Note that Pick<WorkspaceWorkflowTransition, "transition_state_id"> stays optional, so add Required<...> if the API requires the field.

As per coding guidelines: "Use TypeScript interfaces for entity models with separate Create/Update DTOs using `Pick`, `Omit`, and `Partial`".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/WorkspaceWorkflow.ts` around lines 54 - 70, Derive the workflow
DTO fields from the entity models instead of redeclaring them. Update
CreateWorkspaceWorkflow and UpdateWorkspaceWorkflow to use Pick and
Partial<Pick> from WorkspaceWorkflow, preserving required creation fields and
optional update fields; apply the same pattern to
CreateWorkspaceWorkflowTransition and UpdateWorkspaceWorkflowTransition using
WorkspaceWorkflowTransition, keeping state_id as the only non-entity field and
making transition_state_id required only if the API contract requires it.

Source: Coding guidelines


14-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove state_id or soften the doc comment.

The doc comment states that the API never sends state_id on these rows. Line 16 still declares the field. Consumers may branch on it and always read undefined. Either drop line 16 or document why the field remains declared.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/WorkspaceWorkflow.ts` around lines 14 - 22, Update
WorkspaceWorkflowState to resolve the mismatch between the API contract and the
type definition: either remove the state_id field from the interface or clearly
document in the WorkspaceWorkflowState declaration why it remains present
despite the API never populating it. Keep the existing id, type,
allow_issue_creation, is_default, sequence, and transitions members unchanged.
src/api/WorkspaceStates.ts (2)

75-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename delete to del.

delete is a standard resource method. The API resource rule requires the name del. Update the workspace-state tests and public examples with the new method name.

As per coding guidelines, “Standard resource methods should be named: list, create, retrieve, update, del.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/WorkspaceStates.ts` around lines 75 - 76, Rename the WorkspaceStates
resource method from delete to del, preserving its existing HTTP DELETE behavior
and signature. Update all workspace-state tests and public examples to call del
instead of delete, including any references to the renamed method.

Source: Coding guidelines


1-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use kebab-case names for the new modules.

The new module paths use PascalCase filenames. Rename the files and update each import or export path.

  • src/api/WorkspaceStates.ts#L1-L4: Rename WorkspaceStates.ts to workspace-states.ts.
  • src/api/WorkspaceWorkflows/States.ts#L1-L8: Rename States.ts to states.ts.
  • src/models/index.ts#L41-L42: Update exports after renaming WorkspaceWorkflow.ts and WorkItemTypeGovernance.ts.
  • src/client/plane-client.ts#L34-L36: Update the WorkspaceStates import after the file rename.
  • src/index.ts#L46-L48: Update public resource exports after file renames.
  • src/index.ts#L85-L92: Update sub-resource exports after file renames.

As per coding guidelines, “Use kebab-case for file names.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/WorkspaceStates.ts` around lines 1 - 4, Rename the new modules to
kebab-case: src/api/WorkspaceStates.ts to src/api/workspace-states.ts and
src/api/WorkspaceWorkflows/States.ts to src/api/WorkspaceWorkflows/states.ts.
Update all corresponding import and export paths in src/models/index.ts
(including renamed WorkspaceWorkflow.ts and WorkItemTypeGovernance.ts),
src/client/plane-client.ts, and both public and sub-resource export sections of
src/index.ts.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/Workflows/Hooks.ts`:
- Line 1: Rename the Hooks.ts module to kebab-case as hooks.ts, and update the
import in the Workflows index entrypoint to point to the new filename. Keep the
existing exported symbols such as BaseResource unchanged; only adjust the file
name and the corresponding import reference so the workflow API continues to
resolve correctly.

In `@src/api/Workflows/index.ts`:
- Around line 75-76: Rename the Workflows resource method `delete` to `del`,
preserving its existing parameters, return type, and HTTP deletion behavior.
Update the corresponding workflow unit test invocation to use
`client.workflows.del(...)`.

In `@src/api/WorkItemTypeGovernance/Pins.ts`:
- Around line 1-3: Rename src/api/WorkItemTypeGovernance/Pins.ts to pins.ts and
update every import or export referencing it; rename
src/api/WorkItemTypeGovernance/ProjectWorkflows.ts to project-workflows.ts and
update every corresponding import or export, preserving the existing module
symbols and behavior.
- Around line 45-46: Rename the public deletion method in the Pins resource from
delete to del, preserving its parameters, return type, and existing httpDelete
request path so it conforms to the standard resource method contract.

In `@src/api/WorkspaceWorkflows/index.ts`:
- Around line 86-88: Rename the public WorkspaceWorkflows method `delete` to
`del` to match the standard resource API and sibling resources such as
`Transitions.del` and `Hooks.del`; update its call site in the workspace
workflow unit test to use `client.workspaceWorkflows.del(...)`.

In `@src/models/Workflow.ts`:
- Around line 101-106: Update the CreateWorkflowTransitionHook type so phase,
handler_name, and config are required by wrapping their Pick in Required, while
keeping is_enabled optional through the existing Partial branch; ensure
Hooks.create consumers reject incomplete bodies.

In `@tests/unit/work-item-types/types.test.ts`:
- Around line 47-50: Replace the direct console.warn in the
workspaceManagedReason handling with the repository-approved test logging
mechanism, preserving the existing skip message and early return. If no suitable
logger exists, add the narrowest approved localized suppression for this
specific warning.

---

Nitpick comments:
In `@src/api/WorkspaceStates.ts`:
- Around line 75-76: Rename the WorkspaceStates resource method from delete to
del, preserving its existing HTTP DELETE behavior and signature. Update all
workspace-state tests and public examples to call del instead of delete,
including any references to the renamed method.
- Around line 1-4: Rename the new modules to kebab-case:
src/api/WorkspaceStates.ts to src/api/workspace-states.ts and
src/api/WorkspaceWorkflows/States.ts to src/api/WorkspaceWorkflows/states.ts.
Update all corresponding import and export paths in src/models/index.ts
(including renamed WorkspaceWorkflow.ts and WorkItemTypeGovernance.ts),
src/client/plane-client.ts, and both public and sub-resource export sections of
src/index.ts.

In `@src/models/WorkspaceWorkflow.ts`:
- Around line 54-70: Derive the workflow DTO fields from the entity models
instead of redeclaring them. Update CreateWorkspaceWorkflow and
UpdateWorkspaceWorkflow to use Pick and Partial<Pick> from WorkspaceWorkflow,
preserving required creation fields and optional update fields; apply the same
pattern to CreateWorkspaceWorkflowTransition and
UpdateWorkspaceWorkflowTransition using WorkspaceWorkflowTransition, keeping
state_id as the only non-entity field and making transition_state_id required
only if the API contract requires it.
- Around line 14-22: Update WorkspaceWorkflowState to resolve the mismatch
between the API contract and the type definition: either remove the state_id
field from the interface or clearly document in the WorkspaceWorkflowState
declaration why it remains present despite the API never populating it. Keep the
existing id, type, allow_issue_creation, is_default, sequence, and transitions
members unchanged.

In `@tests/unit/workspace-workflows/workspace-workflow.test.ts`:
- Around line 86-88: Add coverage in the workspace workflow test around the
existing transitions listing: create a transition, update it, then delete it,
and add one hook creation using the workflow’s hooks API. Assert each operation
succeeds and retain the existing transitions list assertion, using the returned
transition and workflow identifiers for subsequent calls.
- Around line 48-49: Update the “should create a workflow, configure a chain,
and clean up” test to report ungoverned workspaces as skipped rather than
passing with zero assertions. Reuse the conditional helper from
tests/helpers/conditional-tests, selecting an approach that evaluates the
beforeAll-resolved governed value at runtime and preserves the existing test
body for governed workspaces.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 06fc4d65-55e7-45a5-806d-00c7260c0c62

📥 Commits

Reviewing files that changed from the base of the PR and between 8d0c71c and b27219e.

📒 Files selected for processing (31)
  • README.md
  • src/api/WorkItemTypeGovernance/Pins.ts
  • src/api/WorkItemTypeGovernance/ProjectWorkflows.ts
  • src/api/WorkItemTypeGovernance/index.ts
  • src/api/Workflows/Hooks.ts
  • src/api/Workflows/States.ts
  • src/api/Workflows/Transitions.ts
  • src/api/Workflows/index.ts
  • src/api/WorkspaceStates.ts
  • src/api/WorkspaceWorkflows/Hooks.ts
  • src/api/WorkspaceWorkflows/States.ts
  • src/api/WorkspaceWorkflows/Transitions.ts
  • src/api/WorkspaceWorkflows/index.ts
  • src/client/plane-client.ts
  • src/index.ts
  • src/models/State.ts
  • src/models/WorkItemTypeGovernance.ts
  • src/models/Workflow.ts
  • src/models/WorkspaceFeatures.ts
  • src/models/WorkspaceWorkflow.ts
  • src/models/index.ts
  • tests/helpers/governance.ts
  • tests/unit/project-templates.test.ts
  • tests/unit/state.test.ts
  • tests/unit/work-item-type-governance/work-item-type-governance.test.ts
  • tests/unit/work-item-types/project-properties.test.ts
  • tests/unit/work-item-types/properties-options.test.ts
  • tests/unit/work-item-types/types.test.ts
  • tests/unit/workflows/workflow.test.ts
  • tests/unit/workspace-states.test.ts
  • tests/unit/workspace-workflows/workspace-workflow.test.ts

@@ -0,0 +1,102 @@
import { BaseResource } from "../BaseResource";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Rename Hooks.ts to hooks.ts.

This filename is not kebab-case. Update the import in src/api/Workflows/index.ts after the rename. As per coding guidelines, “Use kebab-case for file names.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/Workflows/Hooks.ts` at line 1, Rename the Hooks.ts module to
kebab-case as hooks.ts, and update the import in the Workflows index entrypoint
to point to the new filename. Keep the existing exported symbols such as
BaseResource unchanged; only adjust the file name and the corresponding import
reference so the workflow API continues to resolve correctly.

Source: Coding guidelines

Comment on lines +75 to +76
async delete(workspaceSlug: string, projectId: string, workflowId: string): Promise<void> {
return this.httpDelete(`/workspaces/${workspaceSlug}/projects/${projectId}/workflows/${workflowId}/`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Rename delete to del.

This is a standard resource deletion method. Rename it to del. Update tests/unit/workflows/workflow.test.ts line 255 to call client.workflows.del(...). As per coding guidelines, “Standard resource methods should be named: list, create, retrieve, update, del.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/Workflows/index.ts` around lines 75 - 76, Rename the Workflows
resource method `delete` to `del`, preserving its existing parameters, return
type, and HTTP deletion behavior. Update the corresponding workflow unit test
invocation to use `client.workflows.del(...)`.

Source: Coding guidelines

Comment on lines +1 to +3
import { BaseResource } from "../BaseResource";
import { Configuration } from "../../Configuration";
import { CreateWorkItemTypeWorkflowPins, WorkItemTypeWorkflowPin } from "../../models/WorkItemTypeGovernance";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use kebab-case filenames for these API modules.

Rename the files and update their imports.

  • src/api/WorkItemTypeGovernance/Pins.ts#L1-L3: rename Pins.ts to pins.ts.
  • src/api/WorkItemTypeGovernance/ProjectWorkflows.ts#L1-L9: rename ProjectWorkflows.ts to project-workflows.ts.

As per coding guidelines: src/**/*.ts: Use kebab-case for file names.

📍 Affects 2 files
  • src/api/WorkItemTypeGovernance/Pins.ts#L1-L3 (this comment)
  • src/api/WorkItemTypeGovernance/ProjectWorkflows.ts#L1-L9
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/WorkItemTypeGovernance/Pins.ts` around lines 1 - 3, Rename
src/api/WorkItemTypeGovernance/Pins.ts to pins.ts and update every import or
export referencing it; rename src/api/WorkItemTypeGovernance/ProjectWorkflows.ts
to project-workflows.ts and update every corresponding import or export,
preserving the existing module symbols and behavior.

Source: Coding guidelines

Comment on lines +45 to +46
async delete(workspaceSlug: string, typeId: string, pinId: string): Promise<void> {
return this.httpDelete(`/workspaces/${workspaceSlug}/work-item-types/${typeId}/governance/pins/${pinId}/`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Rename delete to del.

Line 45 exposes a standard resource deletion method as delete. Use del to match the SDK resource contract.

Proposed fix
-  async delete(workspaceSlug: string, typeId: string, pinId: string): Promise<void> {
+  async del(workspaceSlug: string, typeId: string, pinId: string): Promise<void> {

As per coding guidelines: src/api/**/*.ts: Standard resource methods should be named: list, create, retrieve, update, del.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async delete(workspaceSlug: string, typeId: string, pinId: string): Promise<void> {
return this.httpDelete(`/workspaces/${workspaceSlug}/work-item-types/${typeId}/governance/pins/${pinId}/`);
async del(workspaceSlug: string, typeId: string, pinId: string): Promise<void> {
return this.httpDelete(`/workspaces/${workspaceSlug}/work-item-types/${typeId}/governance/pins/${pinId}/`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/WorkItemTypeGovernance/Pins.ts` around lines 45 - 46, Rename the
public deletion method in the Pins resource from delete to del, preserving its
parameters, return type, and existing httpDelete request path so it conforms to
the standard resource method contract.

Source: Coding guidelines

Comment on lines +86 to +88
async delete(workspaceSlug: string, workflowId: string): Promise<void> {
return this.httpDelete(`/workspaces/${workspaceSlug}/workflows/${workflowId}/`);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Rename delete to del.

The sibling sub-resources in this directory use del (Transitions.del, Hooks.del). This class uses delete, so the public surface is inconsistent. Rename it now to avoid a breaking change later. Update the call site at tests/unit/workspace-workflows/workspace-workflow.test.ts line 27.

♻️ Proposed rename
-  async delete(workspaceSlug: string, workflowId: string): Promise<void> {
+  async del(workspaceSlug: string, workflowId: string): Promise<void> {
     return this.httpDelete(`/workspaces/${workspaceSlug}/workflows/${workflowId}/`);
   }
// tests/unit/workspace-workflows/workspace-workflow.test.ts
await client.workspaceWorkflows.del(workspaceSlug, workflow.id);
As per coding guidelines: "Standard resource methods should be named: `list`, `create`, `retrieve`, `update`, `del`".
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async delete(workspaceSlug: string, workflowId: string): Promise<void> {
return this.httpDelete(`/workspaces/${workspaceSlug}/workflows/${workflowId}/`);
}
async del(workspaceSlug: string, workflowId: string): Promise<void> {
return this.httpDelete(`/workspaces/${workspaceSlug}/workflows/${workflowId}/`);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/WorkspaceWorkflows/index.ts` around lines 86 - 88, Rename the public
WorkspaceWorkflows method `delete` to `del` to match the standard resource API
and sibling resources such as `Transitions.del` and `Hooks.del`; update its call
site in the workspace workflow unit test to use
`client.workspaceWorkflows.del(...)`.

Source: Coding guidelines

Comment thread src/models/Workflow.ts
Comment on lines +101 to +106
/**
* Request model for creating a workflow transition hook. `phase` and
* `handler_name` are immutable post-create.
*/
export type CreateWorkflowTransitionHook = Pick<WorkflowTransitionHook, "phase" | "handler_name" | "config"> &
Partial<Pick<WorkflowTransitionHook, "is_enabled">>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does TypeScript Pick preserve optional property modifiers from the source type?

💡 Result:

Yes, the TypeScript Pick utility type preserves optional property modifiers, provided that the source type is a single object type [1][2]. Because Pick is implemented as a homomorphic (structure-preserving) mapped type, it automatically propagates property modifiers—including optional (?) and readonly modifiers—from the source type to the resulting type [1][2]. However, there is a known limitation regarding union types: when Pick is used on a union of object types, it may not preserve optional modifiers as expected, often causing properties to become required in the resulting type [3][4]. This occurs because the mapping behavior that enables modifier preservation is specifically optimized for mapping over the keys of a single type (e.g., keyof T), rather than the union of keys from multiple types [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate Workflow.ts and Hooks files =="
fd -a 'Workflow\.ts$|Hooks\.ts$' . | sed 's#^\./##' | sort

echo
echo "== WorkflowTransitionHook occurrences =="
rg -n "WorkflowTransitionHook|CreateWorkflowTransitionHook|interface|type .*Transition" src/models src/api -S || true

echo
echo "== Inspect relevant files =="
for f in $(fd 'Workflow\.ts$|Hooks\.ts$' src | sort); do
  echo "--- $f ($(wc -l < "$f") lines) ---"
  ast-grep outline "$f" --view compact || true
done

Repository: makeplane/plane-node-sdk

Length of output: 23476


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/models/Workflow.ts lines 81-110 =="
sed -n '81,110p' src/models/Workflow.ts | nl -ba -v81

echo
echo "== Workflow API hooks create signatures and bodies =="
for f in src/api/Workflows/Hooks.ts src/api/WorkspaceWorkflows/Hooks.ts; do
  echo "--- $f lines 45-58 ---"
  sed -n '45,58p' "$f" | nl -ba -v45
done

echo
echo "== TypeScript Pick optional modifier probe =="
node - <<'JS'
const ts = require('typescript');
function identity(x) { return x; }
const fs = require('fs');
const temp = '/tmp/probe-pick-optional.ts';
fs.writeFileSync(temp, `
interface Source {
  required: string;
  optional?: string;
}
declare function post<T>(data: T): T;
type Create = Pick<Source, "required" | "optional">;
post<Create>({});
`);
const host = ts.createCompilerHost({ strict: true, noEmit: true });
host.getFileNames = () => [temp];
host.read = (name) => name === temp ? fs.readFileSync(temp, 'utf8') : host.readFile(name);
const compiler = ts.createProgram([temp], { strict: true, noEmit: true, target: ts.ScriptTarget.Latest }, host);
const diagnostics = ts.getPreEmitDiagnostics(compiler);
for (const d of diagnostics) {
  const s = typeof d.file?.printLine === 'function'
    ? ts.stringifyDiagnosticMessageText(d.file.printLine(d.file.getLineAndCharacterOfPosition(d.start ?? 0), d.messageText))
    : String(d.messageText);
  console.log(`${d.file?.fileName ?? 'unknown'}:${d.start}:${d.length ?? 0} ${s}`);
}
fs.unlinkSync(temp);
JS

Repository: makeplane/plane-node-sdk

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/models/Workflow.ts lines 81-110 =="
sed -n '81,110p' src/models/Workflow.ts

echo
echo "== Workflow API hooks create signatures and bodies =="
sed -n '45,58p' src/api/Workflows/Hooks.ts
echo "---"
sed -n '53,58p' src/api/WorkspaceWorkflows/Hooks.ts

echo
echo "== TypeScript Pick optional modifier probe =="
if command -v node >/dev/null 2>&1 && node -e "require.resolve('typescript')" >/dev/null 2>&1; then
  node - <<'JS'
const ts = require('typescript');
const fs = require('fs');
const temp = '/tmp/probe-pick-optional.ts';
fs.writeFileSync(temp, `
interface Source {
  required: string;
  optional?: string;
}
declare function post<T>(data: T): T;
type Create = Pick<Source, "required" | "optional">;
post<Create>({});
`);
const host = ts.createCompilerHost({ strict: true, noEmit: true });
host.getFileNames = () => [temp];
host.readFile = (name) => name === temp ? fs.readFileSync(temp, 'utf8') : null;
host.useCaseSensitiveFileNames = () => true;
host.fileExists = (name) => name === temp;
const compiler = ts.createProgram([temp], { strict: true, noEmit: true, target: ts.ScriptTarget.Latest }, host);
let any = false;
const diagnostics = ts.getPreEmitDiagnostics(compiler);
for (const d of diagnostics) any = true;
console.log('node_modules/typescript present: true');
console.log(diagnostics.map(d => String(d.messageText)).join('\n'));
console.log('has diagnostics:', any);
fs.unlinkSync(temp);
JS
else
  echo "node_modules/typescript not present; using TypeScript compiler semantics from compiler source"
  node - <<'JS'
const ts = require('typescript');
const text = `type Source = { required: string; optional?: string}; type Picked = Pick<Source, "optional">;`;
const sourceFile = ts.createSourceFile('probe.ts', text, ts.ScriptTarget.Latest, true);
const program = ts.createProgram(['probe.ts'], {}, {
  getSourceFile(name) { return name === 'probe.ts' ? sourceFile : undefined; },
  fileExists() { return true; },
  readFile() { return text; },
  getCurrentDirectory() { return ''; },
  getDirectories() { return []; },
  getCanonicalFileName(f) { return f; },
  useCaseSensitiveFileNames() { return false; },
  getNewLine() { return '\n'; },
  resolveModuleNames() { return []; },
});
const type = program.getTypeAtLocation(sourceFile);
console.log(ts.typeToString(type));
JS
fi

Repository: makeplane/plane-node-sdk

Length of output: 2476


Make create fields required on CreateWorkflowTransitionHook.

phase, handler_name, and config stay optional because they are optional on WorkflowTransitionHook and Pick preserves that modifier. This makes Hooks.create in src/api/Workflows/Hooks.ts and src/api/WorkspaceWorkflows/Hooks.ts typecheck incomplete bodies like {} or { is_enabled: false }. Wrap the required fields with Required.

🐛 Proposed fix
-export type CreateWorkflowTransitionHook = Pick<WorkflowTransitionHook, "phase" | "handler_name" | "config"> &
-  Partial<Pick<WorkflowTransitionHook, "is_enabled">>;
+export type CreateWorkflowTransitionHook = Required<
+  Pick<WorkflowTransitionHook, "phase" | "handler_name" | "config">
+> &
+  Partial<Pick<WorkflowTransitionHook, "is_enabled">>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Request model for creating a workflow transition hook. `phase` and
* `handler_name` are immutable post-create.
*/
export type CreateWorkflowTransitionHook = Pick<WorkflowTransitionHook, "phase" | "handler_name" | "config"> &
Partial<Pick<WorkflowTransitionHook, "is_enabled">>;
/**
* Request model for creating a workflow transition hook. `phase` and
* `handler_name` are immutable post-create.
*/
export type CreateWorkflowTransitionHook = Required<
Pick<WorkflowTransitionHook, "phase" | "handler_name" | "config">
> &
Partial<Pick<WorkflowTransitionHook, "is_enabled">>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/Workflow.ts` around lines 101 - 106, Update the
CreateWorkflowTransitionHook type so phase, handler_name, and config are
required by wrapping their Pick in Required, while keeping is_enabled optional
through the existing Partial branch; ensure Hooks.create consumers reject
incomplete bodies.

Comment on lines +47 to +50
const reason = workspaceManagedReason(error);
if (reason !== null) {
console.warn("Skipped: project-level work item types are managed at the workspace level —", reason);
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the lint violation.

Line 49 triggers eslint(no-console). Use the test logging mechanism accepted by the repository, or add an approved localized suppression.

🧰 Tools
🪛 GitHub Check: build-lint

[warning] 49-49: eslint(no-console)
Unexpected console statement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/work-item-types/types.test.ts` around lines 47 - 50, Replace the
direct console.warn in the workspaceManagedReason handling with the
repository-approved test logging mechanism, preserving the existing skip message
and early return. If no suitable logger exists, add the narrowest approved
localized suppression for this specific warning.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant