mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 04:02:18 +01:00
feat: add issue privacy ACL foundation
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
0f12721ee9
commit
cd86192ca2
24 files changed
+709
-21
No files matched your search
@@ -857,6 +857,10 @@ export type {
|
||||
ExternalObjectSummaryItem,
|
||||
CompactIssue,
|
||||
Issue,
|
||||
IssueVisibility,
|
||||
IssueAccessGrant,
|
||||
IssueAccessGrantSubjectType,
|
||||
IssueAccessGrantSource,
|
||||
IssueChangeReceiptEntry,
|
||||
IssueChanges,
|
||||
IssueAssigneeAdapterOverrides,
|
||||
|
||||
@@ -559,6 +559,10 @@ export type {
|
||||
IssueSubtreeDiagnosticNode,
|
||||
IssueSubtreeDiagnosticEdge,
|
||||
IssueSubtreeDiagnosticsResponse,
|
||||
IssueVisibility,
|
||||
IssueAccessGrant,
|
||||
IssueAccessGrantSubjectType,
|
||||
IssueAccessGrantSource,
|
||||
IssueBlockerAttention,
|
||||
IssueBlockerAttentionReason,
|
||||
IssueBlockerAttentionState,
|
||||
|
||||
@@ -40,6 +40,22 @@ import type {
|
||||
|
||||
export type { IssueWorkMode };
|
||||
|
||||
export type IssueVisibility = "open" | "private";
|
||||
export type IssueAccessGrantSubjectType = "user" | "agent";
|
||||
export type IssueAccessGrantSource = "explicit" | "assignment" | "project";
|
||||
|
||||
export interface IssueAccessGrant {
|
||||
id: string;
|
||||
issueId: string;
|
||||
subjectType: IssueAccessGrantSubjectType;
|
||||
subjectId: string;
|
||||
source: IssueAccessGrantSource;
|
||||
grantedByUserId: string | null;
|
||||
grantedByAgentId: string | null;
|
||||
createdAt: Date;
|
||||
revokedAt: Date | null;
|
||||
}
|
||||
|
||||
export interface IssueAncestorProject {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -734,6 +750,9 @@ export interface Issue {
|
||||
projectWorkspaceId: string | null;
|
||||
goalId: string | null;
|
||||
parentId: string | null;
|
||||
/** Present on current API responses; optional for compatibility with older plugin payloads. */
|
||||
visibility?: IssueVisibility;
|
||||
privacyRootIssueId?: string | null;
|
||||
ancestors?: IssueAncestor[];
|
||||
title: string;
|
||||
description: string | null;
|
||||
@@ -818,6 +837,8 @@ export type CompactIssue = Pick<
|
||||
| "projectWorkspaceId"
|
||||
| "goalId"
|
||||
| "parentId"
|
||||
| "visibility"
|
||||
| "privacyRootIssueId"
|
||||
| "title"
|
||||
| "description"
|
||||
| "status"
|
||||
|
||||
@@ -13,6 +13,13 @@ import {
|
||||
import { createAgentSchema } from "./agent.js";
|
||||
|
||||
describe("issue validators", () => {
|
||||
it("accepts open/private visibility on create and update", () => {
|
||||
expect(createIssueSchema.parse({ title: "Private", visibility: "private" }).visibility).toBe("private");
|
||||
expect(createIssueSchema.parse({ title: "Open" }).visibility).toBe("open");
|
||||
expect(updateIssueSchema.parse({}).visibility).toBeUndefined();
|
||||
expect(updateIssueSchema.parse({ visibility: "private" }).visibility).toBe("private");
|
||||
expect(updateIssueSchema.safeParse({ visibility: "secret" }).success).toBe(false);
|
||||
});
|
||||
it("passes real line breaks through unchanged", () => {
|
||||
const parsed = createIssueSchema.parse({
|
||||
title: "Follow up PR",
|
||||
|
||||
@@ -427,6 +427,7 @@ const createIssueBaseSchema = z.object({
|
||||
projectWorkspaceId: z.string().uuid().optional().nullable(),
|
||||
goalId: z.string().uuid().optional().nullable(),
|
||||
parentId: z.string().uuid().optional().nullable(),
|
||||
visibility: z.enum(["open", "private"]).optional().default("open"),
|
||||
blockedByIssueIds: z.array(z.string().uuid()).optional(),
|
||||
unblockDescriptor: z.object({
|
||||
owner: z.union([
|
||||
@@ -535,7 +536,9 @@ export const updateIssueSchema = createIssueBaseSchema.omit({
|
||||
createdByUserId: true,
|
||||
responsibleUserId: true,
|
||||
watchdog: true,
|
||||
visibility: true,
|
||||
}).partial().extend({
|
||||
visibility: z.enum(["open", "private"]).optional(),
|
||||
requestDepth: issueRequestDepthInputSchema.optional(),
|
||||
assigneeAgentId: z.string().trim().min(1).optional().nullable(),
|
||||
comment: multilineTextSchema.pipe(z.string().min(1)).optional(),
|
||||
|
||||
Reference in new issue
Block a user