@maudecode/kanvil 0.4.2 → 0.4.3
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.
|
@@ -1700,11 +1700,10 @@ async function rememberLabelColor(ctx, color) {
|
|
|
1700
1700
|
async function changeLabelUsage(ctx, name, replacement) {
|
|
1701
1701
|
const affected = await ctx.db.select().from(tickets).where(and(eq(tickets.projectId, project(ctx).id), sql`${name} = ANY(${tickets.labels})`));
|
|
1702
1702
|
const pending = [];
|
|
1703
|
-
for (const ticket of affected) pending.push((await
|
|
1704
|
-
projectId: project(ctx).id,
|
|
1703
|
+
for (const ticket of affected) pending.push((await updateTicketLabelsForDefinition(ctx, {
|
|
1705
1704
|
ticketId: ticket.id,
|
|
1706
1705
|
expectedVersion: ticket.version,
|
|
1707
|
-
|
|
1706
|
+
labels: [...new Set(replacement ? ticket.labels.map((tag) => tag === name ? replacement : tag) : ticket.labels.filter((tag) => tag !== name))]
|
|
1708
1707
|
})).event);
|
|
1709
1708
|
await publishMany(ctx, pending);
|
|
1710
1709
|
await rewriteViewFilters(ctx, "label", (tag) => tag !== name ? tag : replacement ?? null);
|
|
@@ -2277,15 +2276,24 @@ async function updateTicketRow(ctx, input) {
|
|
|
2277
2276
|
const current = await getTicket(ctx, input.ticketId);
|
|
2278
2277
|
assertVersion(current, input.expectedVersion, "ticket");
|
|
2279
2278
|
await assertWorkerClaim(ctx, current, input.claimId);
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2279
|
+
return persistTicketChanges(ctx, current, input.changes);
|
|
2280
|
+
}
|
|
2281
|
+
async function updateTicketLabelsForDefinition(ctx, input) {
|
|
2282
|
+
if (!can(ctx, "project.manage") && !can(ctx, "workspace.manage")) fail(403, "forbidden", "Label administration permission is required");
|
|
2283
|
+
const current = await getTicket(ctx, input.ticketId);
|
|
2284
|
+
assertVersion(current, input.expectedVersion, "ticket");
|
|
2285
|
+
return persistTicketChanges(ctx, current, { labels: input.labels });
|
|
2286
|
+
}
|
|
2287
|
+
async function persistTicketChanges(ctx, current, changes) {
|
|
2288
|
+
await validateReferences(ctx, current.id, changes);
|
|
2289
|
+
const state = await resolveState(ctx, changes, current);
|
|
2290
|
+
const { startAt, dueAt, customFields, ...values } = changes, dates = dateColumns({
|
|
2283
2291
|
startAt,
|
|
2284
2292
|
dueAt
|
|
2285
2293
|
});
|
|
2286
2294
|
assertSchedule(dates.startAt === void 0 ? current.startAt : dates.startAt, dates.dueAt === void 0 ? current.dueAt : dates.dueAt, current.key);
|
|
2287
2295
|
const row = one(await ctx.db.update(tickets).set({
|
|
2288
|
-
...
|
|
2296
|
+
...values,
|
|
2289
2297
|
...state,
|
|
2290
2298
|
...dates,
|
|
2291
2299
|
...customFields && { customFields: applyCustomFieldValues(await projectCustomFields(ctx), current.customFields, customFields) },
|
|
@@ -2300,7 +2308,7 @@ async function updateTicketRow(ctx, input) {
|
|
|
2300
2308
|
ticketId: row.id,
|
|
2301
2309
|
data: {
|
|
2302
2310
|
version: row.version,
|
|
2303
|
-
changedFields: [.../* @__PURE__ */ new Set([...Object.keys(
|
|
2311
|
+
changedFields: [.../* @__PURE__ */ new Set([...Object.keys(changes), ...state ? ["status", "stateId"] : []])]
|
|
2304
2312
|
}
|
|
2305
2313
|
}
|
|
2306
2314
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as auth_schema_exports, d as user$1, i as apikey, n as createDatabase, r as account, t as readConfig, u as session } from "./config-DOT1SDQO.mjs";
|
|
2
2
|
import { A as hasAdminRole, B as memberSchema, C as errorSchema, Ft as photoInputSchema, G as notificationReadInput, H as notificationIdsInput, I as isOperation, It as photoResultSchema, L as isPresetColor, Lt as s3SettingsSchema, M as importProviderDefinitions, Nt as brokerSettingsSchema, Pt as instanceUpdateSchema, R as isPublicOperation, U as notificationPreferencesInput, W as notificationPreferencesSchema, Y as operations, at as publicOperations, c as credentialInput, g as defaultWorkflow, ht as scopes, j as importLimits, jt as adminInstanceSchema, mt as roles, ot as pushDeviceInput, q as okSchema, s as closedStates, t as ApiError, wt as ticketExportFormat, xt as stateLabels, zt as searchSettingsSchema } from "./src-VxR5jZiK.mjs";
|
|
3
3
|
import { t as migrateDatabase } from "./migrate-C9f4ozB4.mjs";
|
|
4
|
-
import { $ as subscriptions, A as createTicketSearch, B as blobObjects, C as DeliveryError, D as requireInstanceAdmin, E as createWriteLimiter, F as stagedUploadCutoff, G as members, H as eventClock, I as createObjectStore, J as profilePhotos, K as notificationPreferences, L as createPollingJob, M as createBlobStorage, N as decodeImage, O as requireSession, P as imageResponse, Q as storageBackends, R as attachmentContent, S as deliverBatch, T as createAccess, U as events, V as deliveryCheckpoints, X as pushDevices, Y as projects, Z as stagedUploads, _ as recipientColumns, a as deliverySecrets, b as receiveRepositoryWebhook, c as ownerBlocker, d as createDomain, et as tickets, f as fail, g as reachable, h as one, i as createInstance, j as createTicketIndex, k as readCalendarFeed, l as appendEvents, m as notify, n as emailCodesAvailable, nt as workspaces, o as otherActiveAdministrator, p as json, q as notifications, r as signInProviders, rt as matchesOIDCBinding, s as ownedWorkspaces, t as createAuth, tt as workspaceMembers, u as assertVersion, v as requireRow, w as createHttpSender, x as defaultSenders, y as processImports, z as attachments } from "./auth-
|
|
4
|
+
import { $ as subscriptions, A as createTicketSearch, B as blobObjects, C as DeliveryError, D as requireInstanceAdmin, E as createWriteLimiter, F as stagedUploadCutoff, G as members, H as eventClock, I as createObjectStore, J as profilePhotos, K as notificationPreferences, L as createPollingJob, M as createBlobStorage, N as decodeImage, O as requireSession, P as imageResponse, Q as storageBackends, R as attachmentContent, S as deliverBatch, T as createAccess, U as events, V as deliveryCheckpoints, X as pushDevices, Y as projects, Z as stagedUploads, _ as recipientColumns, a as deliverySecrets, b as receiveRepositoryWebhook, c as ownerBlocker, d as createDomain, et as tickets, f as fail, g as reachable, h as one, i as createInstance, j as createTicketIndex, k as readCalendarFeed, l as appendEvents, m as notify, n as emailCodesAvailable, nt as workspaces, o as otherActiveAdministrator, p as json, q as notifications, r as signInProviders, rt as matchesOIDCBinding, s as ownedWorkspaces, t as createAuth, tt as workspaceMembers, u as assertVersion, v as requireRow, w as createHttpSender, x as defaultSenders, y as processImports, z as attachments } from "./auth-CnAQzKyq.mjs";
|
|
5
5
|
import { serve } from "@hono/node-server";
|
|
6
6
|
import pg from "pg";
|
|
7
7
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
@@ -325,7 +325,7 @@ function createAccountAdministration(database, auth, config) {
|
|
|
325
325
|
}
|
|
326
326
|
//#endregion
|
|
327
327
|
//#region src/version.ts
|
|
328
|
-
const applicationVersion = "0.4.
|
|
328
|
+
const applicationVersion = "0.4.3";
|
|
329
329
|
//#endregion
|
|
330
330
|
//#region src/realtime.ts
|
|
331
331
|
async function createRealtime(config) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { d as user, n as createDatabase, r as account, t as readConfig, u as session } from "./config-DOT1SDQO.mjs";
|
|
2
2
|
import { A as hasAdminRole } from "./src-VxR5jZiK.mjs";
|
|
3
|
-
import { W as instanceSettings, f as fail, t as createAuth } from "./auth-
|
|
3
|
+
import { W as instanceSettings, f as fail, t as createAuth } from "./auth-CnAQzKyq.mjs";
|
|
4
4
|
import { and, eq, isNull, sql } from "drizzle-orm";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { parseArgs } from "node:util";
|
package/docs/api.md
CHANGED
|
@@ -50,9 +50,9 @@ Use `list_tickets` with `parentId` set to a parent UUID or ticket key to page th
|
|
|
50
50
|
|
|
51
51
|
`list_project_labels` (`GET /api/v1/projects/{projectId}/labels/catalog`) returns the labels the project's tickets can use, with stable IDs, names, colors, versions, and this project's usage counts including archived tickets. Each entry has a `scope`: `project` entries carry `projectId` and belong to the project; `workspace` entries carry `workspaceId` and are shared by every project in the workspace. Unused definitions remain available. Existing ticket label names are backfilled during upgrade as project labels; new freeform labels from ticket writes register automatically as project labels with gray as their color, unless the workspace already defines the name. Ticket payloads continue to use label-name arrays.
|
|
52
52
|
|
|
53
|
-
Project administrators can `create_project_label` (`POST .../labels`), `update_project_label` (`PATCH .../labels/{labelId}`), and `delete_project_label` (`DELETE .../labels/{labelId}`) through HTTP or MCP. Creation takes `name` and optional `color`; updates take `name`, `color`, and `expectedVersion`; deletion takes `expectedVersion`. Renames update every affected ticket, including archived tickets, and saved-view label filters. Deletion removes the label from tickets and removes its filter from saved views, retaining other filters. These changes
|
|
53
|
+
Project administrators can `create_project_label` (`POST .../labels`), `update_project_label` (`PATCH .../labels/{labelId}`), and `delete_project_label` (`DELETE .../labels/{labelId}`) through HTTP or MCP. Creation takes `name` and optional `color`; updates take `name`, `color`, and `expectedVersion`; deletion takes `expectedVersion`. Renames update every affected ticket, including archived tickets, and saved-view label filters. Deletion removes the label from tickets and removes its filter from saved views, retaining other filters. These changes require label-administration permission and commit atomically, increment affected ticket versions, and emit normal `ticket.updated` events plus `label.created`, `label.updated`, or `label.deleted`. Recoloring emits a label event without changing ticket versions. Realtime consumers can refresh the label catalog on label events. Label-definition renames and deletions propagate only labels without requiring or changing affected tickets' worker claims, including completed tickets whose ownership requirement remains recorded. Ordinary ticket and bulk edits still enforce worker ownership; automation readiness and other ticket fields remain unchanged.
|
|
54
54
|
|
|
55
|
-
Workspace administrators manage shared labels with `list_workspace_labels` (`GET /api/v1/workspaces/{workspaceId}/labels`), `create_workspace_label` (`POST .../labels`), `update_workspace_label` (`PATCH .../labels/{labelId}`), and `delete_workspace_label` (`DELETE .../labels/{labelId}`); any workspace member can list them. Inputs match the project operations. List counts include only tickets in projects the caller can read, so private projects never show up in them. A rename or deletion updates tickets, saved-view filters, and calendar feed filters in every project of the workspace in one transaction with
|
|
55
|
+
Workspace administrators manage shared labels with `list_workspace_labels` (`GET /api/v1/workspaces/{workspaceId}/labels`), `create_workspace_label` (`POST .../labels`), `update_workspace_label` (`PATCH .../labels/{labelId}`), and `delete_workspace_label` (`DELETE .../labels/{labelId}`); any workspace member can list them. Inputs match the project operations. List counts include only tickets in projects the caller can read, so private projects never show up in them. A rename or deletion updates tickets, saved-view filters, and calendar feed filters in every project of the workspace in one transaction with label-administration permission and version checks. Worker claims remain unchanged and do not block this label-only propagation; any failed permission or version check rolls the whole change back. The label event goes to each project of the workspace with `scope: "workspace"` and `workspaceId`.
|
|
56
56
|
|
|
57
57
|
Within a workspace a name belongs to the workspace or to projects, never both, so a ticket label always resolves to one color. Creating or renaming a project label onto a workspace label's name fails with `409 duplicate_label`. Creating or renaming a workspace label onto a name that projects already define fails with `409 label_conflict`, whose `details.projects` lists their keys. Retry with `adopt: true` to replace those project definitions: their tickets keep the label and show the workspace color, and a ticket that carries both names after an adopting rename keeps one.
|
|
58
58
|
|