@fieldwangai/agentflow 0.1.115 → 0.1.117
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.
- package/bin/lib/ui-server.mjs +272 -21
- package/builtin/web-ui/dist/assets/index-BKLuP3ZS.css +1 -0
- package/builtin/web-ui/dist/assets/{index-sFdIyhv_.js → index-RzWv0xOo.js} +81 -80
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/web-ui/dist/assets/index-CuRtjhm3.css +0 -1
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -3133,6 +3133,48 @@ function hydrateWorkspaceGraphForRuntime(workspaceRoot, scoped = {}, graph = {},
|
|
|
3133
3133
|
return hydrateWorkspaceSlotMetaFromDefinitions(workspaceRoot, scoped, withMarketplaceRuntime, userCtx);
|
|
3134
3134
|
}
|
|
3135
3135
|
|
|
3136
|
+
function adminWorkspaceOwnerSummary(ownerId = "") {
|
|
3137
|
+
const id = String(ownerId || "").trim();
|
|
3138
|
+
if (!id) return null;
|
|
3139
|
+
const users = readAuthUsers();
|
|
3140
|
+
const knownUserIds = new Set([
|
|
3141
|
+
...Object.keys(users || {}),
|
|
3142
|
+
...listAgentflowUserIds(),
|
|
3143
|
+
].map((value) => String(value || "").trim()).filter(Boolean));
|
|
3144
|
+
if (!knownUserIds.has(id)) return null;
|
|
3145
|
+
return {
|
|
3146
|
+
userId: id,
|
|
3147
|
+
username: String(users?.[id]?.username || id),
|
|
3148
|
+
};
|
|
3149
|
+
}
|
|
3150
|
+
|
|
3151
|
+
function adminWorkspaceRequestedUserContext(userCtx = {}) {
|
|
3152
|
+
const ownerId = String(userCtx.adminOwnerId || "").trim();
|
|
3153
|
+
if (!ownerId) return { userCtx };
|
|
3154
|
+
if (userCtx.isAdmin !== true) {
|
|
3155
|
+
return { error: "Admin permission required", status: 403 };
|
|
3156
|
+
}
|
|
3157
|
+
const owner = adminWorkspaceOwnerSummary(ownerId);
|
|
3158
|
+
if (!owner) return { error: "Workspace owner not found", status: 404 };
|
|
3159
|
+
return {
|
|
3160
|
+
owner,
|
|
3161
|
+
userCtx: {
|
|
3162
|
+
...userCtx,
|
|
3163
|
+
userId: owner.userId,
|
|
3164
|
+
adminOwnerId: "",
|
|
3165
|
+
},
|
|
3166
|
+
};
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
function workspaceScopedUserContext(scoped = {}, userCtx = {}) {
|
|
3170
|
+
if (!scoped.adminReadonly || !scoped.ownerUserId) return userCtx;
|
|
3171
|
+
return {
|
|
3172
|
+
...userCtx,
|
|
3173
|
+
userId: scoped.ownerUserId,
|
|
3174
|
+
adminOwnerId: "",
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3136
3178
|
function resolveWorkspaceScopeRoot(workspaceRoot, params = {}, opts = {}) {
|
|
3137
3179
|
const flowId = params.flowId != null ? String(params.flowId).trim() : "";
|
|
3138
3180
|
if (!flowId) return { root: path.resolve(workspaceRoot), flowId: "", flowSource: "", archived: false };
|
|
@@ -3143,6 +3185,46 @@ function resolveWorkspaceScopeRoot(workspaceRoot, params = {}, opts = {}) {
|
|
|
3143
3185
|
if (!isValidFlowSourceRead(flowSource)) {
|
|
3144
3186
|
return { root: "", error: "Invalid flowSource" };
|
|
3145
3187
|
}
|
|
3188
|
+
const adminOwnerId = String(params.adminOwnerId || opts.adminOwnerId || "").trim();
|
|
3189
|
+
if (adminOwnerId) {
|
|
3190
|
+
if (opts.isAdmin !== true) {
|
|
3191
|
+
return { root: "", error: "Admin permission required", status: 403 };
|
|
3192
|
+
}
|
|
3193
|
+
if (flowSource !== "user") {
|
|
3194
|
+
return { root: "", error: "Admin read-only review only supports user projects", status: 400 };
|
|
3195
|
+
}
|
|
3196
|
+
const owner = adminWorkspaceOwnerSummary(adminOwnerId);
|
|
3197
|
+
if (!owner) {
|
|
3198
|
+
return { root: "", error: "Workspace owner not found", status: 404 };
|
|
3199
|
+
}
|
|
3200
|
+
const targetFlow = listFlowsJson(workspaceRoot, { userId: owner.userId })
|
|
3201
|
+
.find((flow) => (
|
|
3202
|
+
flow.id === flowId
|
|
3203
|
+
&& (flow.source || "user") === "user"
|
|
3204
|
+
&& Boolean(flow.archived) === archived
|
|
3205
|
+
));
|
|
3206
|
+
if (!targetFlow?.path) {
|
|
3207
|
+
return { root: "", error: "Pipeline workspace not found", status: 404 };
|
|
3208
|
+
}
|
|
3209
|
+
return {
|
|
3210
|
+
root: path.resolve(targetFlow.path),
|
|
3211
|
+
flowId,
|
|
3212
|
+
flowSource: "user",
|
|
3213
|
+
requestedFlowSource: flowSource,
|
|
3214
|
+
workspaceId: "",
|
|
3215
|
+
archived,
|
|
3216
|
+
collaboration: null,
|
|
3217
|
+
collaborationAccess: {
|
|
3218
|
+
allowed: true,
|
|
3219
|
+
writable: false,
|
|
3220
|
+
runnable: false,
|
|
3221
|
+
role: "admin-viewer",
|
|
3222
|
+
},
|
|
3223
|
+
adminReadonly: true,
|
|
3224
|
+
ownerUserId: owner.userId,
|
|
3225
|
+
ownerUsername: owner.username,
|
|
3226
|
+
};
|
|
3227
|
+
}
|
|
3146
3228
|
const workspaceId = String(params.workspaceId || "").trim();
|
|
3147
3229
|
let collaboration = getWorkspaceCollaborationForProject({
|
|
3148
3230
|
workspaceId,
|
|
@@ -7472,6 +7554,17 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
|
|
|
7472
7554
|
const flowId = String(params.flowId || "").trim();
|
|
7473
7555
|
const flowSource = String(params.flowSource || "user").trim() || "user";
|
|
7474
7556
|
const archived = params.archived === true || params.archived === "1" || params.flowArchived === true;
|
|
7557
|
+
const adminOwnerId = String(params.adminOwnerId || userCtx.adminOwnerId || "").trim();
|
|
7558
|
+
if (adminOwnerId && userCtx.isAdmin !== true) {
|
|
7559
|
+
return { error: "Admin permission required", status: 403 };
|
|
7560
|
+
}
|
|
7561
|
+
const adminOwner = adminOwnerId ? adminWorkspaceOwnerSummary(adminOwnerId) : null;
|
|
7562
|
+
if (adminOwnerId && !adminOwner) {
|
|
7563
|
+
return { error: "Workspace owner not found", status: 404 };
|
|
7564
|
+
}
|
|
7565
|
+
if (adminOwner && capability !== "read") {
|
|
7566
|
+
return { error: "Admin Workspace review is read-only", status: 403 };
|
|
7567
|
+
}
|
|
7475
7568
|
const shareToken = String(params.workflowShare || params.workflow_share || "").trim();
|
|
7476
7569
|
const linkCollaboration = shareToken ? getPrdWorkflowCollaborationByShareToken(shareToken) : null;
|
|
7477
7570
|
if (shareToken && (!linkCollaboration || linkCollaboration.tapdId !== tapdId)) {
|
|
@@ -7480,8 +7573,10 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
|
|
|
7480
7573
|
const memberCollaboration = tapdId
|
|
7481
7574
|
? getPrdWorkflowCollaborationForUser(tapdId, userCtx?.userId)
|
|
7482
7575
|
: null;
|
|
7483
|
-
const collaboration = linkCollaboration || memberCollaboration;
|
|
7484
|
-
const access =
|
|
7576
|
+
const collaboration = adminOwner ? null : (linkCollaboration || memberCollaboration);
|
|
7577
|
+
const access = adminOwner
|
|
7578
|
+
? { allowed: true, writable: false, role: "admin-viewer", via: "admin-review" }
|
|
7579
|
+
: linkCollaboration
|
|
7485
7580
|
? { allowed: true, writable: false, role: "viewer", via: "share-link" }
|
|
7486
7581
|
: prdWorkflowCollaborationAccess(collaboration, userCtx?.userId);
|
|
7487
7582
|
if (collaboration && !access.allowed) {
|
|
@@ -7490,7 +7585,7 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
|
|
|
7490
7585
|
if (capability === "write" && (linkCollaboration || (collaboration && !access.writable))) {
|
|
7491
7586
|
return { error: "PRD Workflow collaboration edit permission denied", status: 403 };
|
|
7492
7587
|
}
|
|
7493
|
-
const ownerId = String(collaboration?.ownerId || userCtx?.userId || "").trim();
|
|
7588
|
+
const ownerId = String(adminOwner?.userId || collaboration?.ownerId || userCtx?.userId || "").trim();
|
|
7494
7589
|
const stateRoot = path.resolve(getAgentflowUserDataRoot(ownerId));
|
|
7495
7590
|
let executionRoot = path.resolve(workspaceRoot);
|
|
7496
7591
|
if (flowId) {
|
|
@@ -7498,6 +7593,7 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
|
|
|
7498
7593
|
flowId,
|
|
7499
7594
|
flowSource,
|
|
7500
7595
|
workspaceId: params.workspaceId || "",
|
|
7596
|
+
adminOwnerId,
|
|
7501
7597
|
archived,
|
|
7502
7598
|
}, userCtx);
|
|
7503
7599
|
if (projectScope.error) {
|
|
@@ -7516,6 +7612,7 @@ function resolvePrdWorkflowScope(workspaceRoot, params = {}, userCtx = {}, capab
|
|
|
7516
7612
|
collaborationAccess: access,
|
|
7517
7613
|
shareToken,
|
|
7518
7614
|
sharedByLink: Boolean(linkCollaboration),
|
|
7615
|
+
adminReadonly: Boolean(adminOwner),
|
|
7519
7616
|
flowId,
|
|
7520
7617
|
flowSource,
|
|
7521
7618
|
archived,
|
|
@@ -7526,7 +7623,8 @@ function prdWorkflowKey(userCtx = {}, flowSource = "user", flowId = "", tapdId =
|
|
|
7526
7623
|
const id = String(tapdId || "").trim();
|
|
7527
7624
|
const collaboration = getPrdWorkflowCollaborationByShareToken(shareToken)
|
|
7528
7625
|
|| getPrdWorkflowCollaborationForUser(id, userCtx?.userId);
|
|
7529
|
-
const
|
|
7626
|
+
const adminOwnerId = userCtx?.isAdmin === true ? String(userCtx?.adminOwnerId || "").trim() : "";
|
|
7627
|
+
const actorScope = `user:${String(collaboration?.ownerId || adminOwnerId || userCtx?.userId || "")}`;
|
|
7530
7628
|
return [actorScope, id].join("\t");
|
|
7531
7629
|
}
|
|
7532
7630
|
|
|
@@ -7678,6 +7776,32 @@ function prdWorkflowReviewIdFromRequest(tapdId, payload = {}, durability = "temp
|
|
|
7678
7776
|
return prdWorkflowSafeStateId(["review", tapdId, stageHead, digest].filter(Boolean).join("-")).slice(0, 64);
|
|
7679
7777
|
}
|
|
7680
7778
|
|
|
7779
|
+
function prdWorkflowReviewArtifactKey(tapdId, payload = {}, durability = "temporary") {
|
|
7780
|
+
const explicit = String(payload.artifactKey || payload.artifact_key || "").trim();
|
|
7781
|
+
if (explicit) return explicit.slice(0, 500);
|
|
7782
|
+
const issueKey = prdWorkflowSafeStateId(
|
|
7783
|
+
payload.issueKey || payload.issue_key || payload.issue || "global",
|
|
7784
|
+
).toLowerCase();
|
|
7785
|
+
const platform = prdWorkflowSafeStateId(payload.platform || "all").toLowerCase();
|
|
7786
|
+
const stage = prdWorkflowSafeStateId(
|
|
7787
|
+
payload.stage
|
|
7788
|
+
|| payload.stageKey
|
|
7789
|
+
|| payload.stage_key
|
|
7790
|
+
|| payload.action
|
|
7791
|
+
|| payload.actionId
|
|
7792
|
+
|| payload.action_id
|
|
7793
|
+
|| "review",
|
|
7794
|
+
).toLowerCase();
|
|
7795
|
+
return [
|
|
7796
|
+
"prd-review",
|
|
7797
|
+
prdWorkflowSafeStateId(tapdId).toLowerCase(),
|
|
7798
|
+
issueKey,
|
|
7799
|
+
platform,
|
|
7800
|
+
stage,
|
|
7801
|
+
String(durability || "temporary").trim().toLowerCase() || "temporary",
|
|
7802
|
+
].join(":").slice(0, 500);
|
|
7803
|
+
}
|
|
7804
|
+
|
|
7681
7805
|
function prdWorkflowStatePath(scopedRoot, tapdId) {
|
|
7682
7806
|
const rootDir = scopedRoot || process.cwd();
|
|
7683
7807
|
return path.join(rootDir, ".workspace", "prd-flow", "workflow-state", `${prdWorkflowSafeStateId(tapdId)}.json`);
|
|
@@ -9131,18 +9255,27 @@ function prdWorkflowNormalizeRuntimeEvent(tapdId, event = {}) {
|
|
|
9131
9255
|
|
|
9132
9256
|
function prdWorkflowMergeRuntimeEventArrays(left, right) {
|
|
9133
9257
|
const out = [];
|
|
9134
|
-
const seen = new
|
|
9258
|
+
const seen = new Map();
|
|
9135
9259
|
for (const value of [...(Array.isArray(left) ? left : []), ...(Array.isArray(right) ? right : [])]) {
|
|
9136
9260
|
if (value == null) continue;
|
|
9137
|
-
|
|
9261
|
+
const explicitKey = value && typeof value === "object" && !Array.isArray(value)
|
|
9262
|
+
? String(value.key || value.artifactKey || value.artifact_key || "").trim()
|
|
9263
|
+
: "";
|
|
9264
|
+
let key = explicitKey ? `key:${explicitKey}` : "";
|
|
9138
9265
|
try {
|
|
9139
|
-
key = typeof value === "string" ? value : JSON.stringify(value);
|
|
9266
|
+
if (!key) key = typeof value === "string" ? value : JSON.stringify(value);
|
|
9140
9267
|
} catch {
|
|
9141
9268
|
key = String(value);
|
|
9142
9269
|
}
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9270
|
+
const index = seen.get(key);
|
|
9271
|
+
if (index == null) {
|
|
9272
|
+
seen.set(key, out.length);
|
|
9273
|
+
out.push(value);
|
|
9274
|
+
continue;
|
|
9275
|
+
}
|
|
9276
|
+
if (explicitKey) {
|
|
9277
|
+
out[index] = value;
|
|
9278
|
+
}
|
|
9146
9279
|
}
|
|
9147
9280
|
return out;
|
|
9148
9281
|
}
|
|
@@ -10958,7 +11091,11 @@ export function startUiServer({
|
|
|
10958
11091
|
}
|
|
10959
11092
|
|
|
10960
11093
|
const authUser = getAuthUserFromRequest(req);
|
|
10961
|
-
const userCtx = authUser ? {
|
|
11094
|
+
const userCtx = authUser ? {
|
|
11095
|
+
userId: authUser.userId,
|
|
11096
|
+
isAdmin: Boolean(authUser.isAdmin),
|
|
11097
|
+
adminOwnerId: String(url.searchParams.get("adminOwnerId") || "").trim(),
|
|
11098
|
+
} : {};
|
|
10962
11099
|
if (req.method === "GET" && url.pathname === "/api/auth/session-token") {
|
|
10963
11100
|
if (!authUser?.userId) {
|
|
10964
11101
|
json(res, 401, { error: "Unauthorized" });
|
|
@@ -12195,10 +12332,15 @@ export function startUiServer({
|
|
|
12195
12332
|
const shortUrl = shortLink?.shortUrl || "";
|
|
12196
12333
|
const displayUrl = shortUrl || reviewUrl;
|
|
12197
12334
|
const durability = review.durability || "temporary";
|
|
12335
|
+
const artifactKey = prdWorkflowReviewArtifactKey(tapdId, payload, durability);
|
|
12198
12336
|
const reviewSource = review.source && typeof review.source === "object" && !Array.isArray(review.source)
|
|
12199
12337
|
? review.source
|
|
12200
12338
|
: { kind: durability === "durable" ? "ai-doc" : "local-draft", durability };
|
|
12339
|
+
const idempotencyKey = String(
|
|
12340
|
+
payload.idempotencyKey || payload.idempotency_key || "",
|
|
12341
|
+
).trim();
|
|
12201
12342
|
const artifact = {
|
|
12343
|
+
key: artifactKey,
|
|
12202
12344
|
label: payload.artifactLabel || "Markdown Review",
|
|
12203
12345
|
kind: durability === "temporary" ? "temporary-review" : "review",
|
|
12204
12346
|
persistence: "runtime",
|
|
@@ -12222,12 +12364,15 @@ export function startUiServer({
|
|
|
12222
12364
|
detail: "已生成临时 Markdown review 链接",
|
|
12223
12365
|
status: "current",
|
|
12224
12366
|
issueKey: payload.issueKey || payload.issue_key || "",
|
|
12367
|
+
idempotencyKey,
|
|
12225
12368
|
durability,
|
|
12226
12369
|
sourceArtifact: reviewSource,
|
|
12227
12370
|
expiresAt: review.expiresAt || "",
|
|
12228
12371
|
artifacts: [artifact],
|
|
12229
12372
|
links: [{
|
|
12373
|
+
key: artifactKey,
|
|
12230
12374
|
label: "Markdown Review",
|
|
12375
|
+
kind: artifact.kind,
|
|
12231
12376
|
url: displayUrl,
|
|
12232
12377
|
canonicalUrl: reviewUrl,
|
|
12233
12378
|
shortUrl,
|
|
@@ -12647,6 +12792,36 @@ export function startUiServer({
|
|
|
12647
12792
|
return;
|
|
12648
12793
|
}
|
|
12649
12794
|
|
|
12795
|
+
if (req.method === "GET" && url.pathname === "/api/admin/user-workspaces") {
|
|
12796
|
+
if (!authUser?.isAdmin) {
|
|
12797
|
+
json(res, 403, { error: "Admin permission required" });
|
|
12798
|
+
return;
|
|
12799
|
+
}
|
|
12800
|
+
const owner = adminWorkspaceOwnerSummary(url.searchParams.get("userId") || "");
|
|
12801
|
+
if (!owner) {
|
|
12802
|
+
json(res, 404, { error: "Workspace owner not found" });
|
|
12803
|
+
return;
|
|
12804
|
+
}
|
|
12805
|
+
try {
|
|
12806
|
+
const workspaces = listFlowsJson(root, { userId: owner.userId })
|
|
12807
|
+
.filter((flow) => (flow.source || "user") === "user")
|
|
12808
|
+
.map((flow) => ({
|
|
12809
|
+
id: String(flow.id || ""),
|
|
12810
|
+
source: "user",
|
|
12811
|
+
archived: flow.archived === true,
|
|
12812
|
+
description: String(flow.description || ""),
|
|
12813
|
+
ownerUserId: owner.userId,
|
|
12814
|
+
ownerUsername: owner.username,
|
|
12815
|
+
adminReadonly: true,
|
|
12816
|
+
}))
|
|
12817
|
+
.sort((a, b) => Number(a.archived) - Number(b.archived) || a.id.localeCompare(b.id));
|
|
12818
|
+
json(res, 200, { owner, workspaces });
|
|
12819
|
+
} catch (e) {
|
|
12820
|
+
json(res, 500, { error: (e && e.message) || String(e) });
|
|
12821
|
+
}
|
|
12822
|
+
return;
|
|
12823
|
+
}
|
|
12824
|
+
|
|
12650
12825
|
if (req.method === "GET" && url.pathname === "/api/admin/run-detail") {
|
|
12651
12826
|
if (!authUser?.isAdmin) {
|
|
12652
12827
|
json(res, 403, { error: "Admin permission required" });
|
|
@@ -13022,12 +13197,17 @@ export function startUiServer({
|
|
|
13022
13197
|
flowId,
|
|
13023
13198
|
flowSource,
|
|
13024
13199
|
workspaceId: payload.workspaceId || "",
|
|
13200
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
13025
13201
|
archived,
|
|
13026
13202
|
}, userCtx);
|
|
13027
13203
|
if (scoped.error) {
|
|
13028
13204
|
json(res, scoped.status || 400, { error: scoped.error });
|
|
13029
13205
|
return;
|
|
13030
13206
|
}
|
|
13207
|
+
if (scoped.adminReadonly) {
|
|
13208
|
+
json(res, 403, { error: "Admin Workspace review is read-only" });
|
|
13209
|
+
return;
|
|
13210
|
+
}
|
|
13031
13211
|
const ensured = ensureWorkspaceCollaboration({
|
|
13032
13212
|
flowId,
|
|
13033
13213
|
flowSource,
|
|
@@ -13139,7 +13319,12 @@ export function startUiServer({
|
|
|
13139
13319
|
json(res, scoped.status || 400, { error: scoped.error });
|
|
13140
13320
|
return;
|
|
13141
13321
|
}
|
|
13142
|
-
const key = workspaceCollaborationEventKey(
|
|
13322
|
+
const key = workspaceCollaborationEventKey(
|
|
13323
|
+
workspaceScopedUserContext(scoped, userCtx),
|
|
13324
|
+
scoped.flowSource,
|
|
13325
|
+
scoped.flowId,
|
|
13326
|
+
scoped.archived,
|
|
13327
|
+
);
|
|
13143
13328
|
let subscribers = workspaceCollaborationSubscribers.get(key);
|
|
13144
13329
|
if (!subscribers) {
|
|
13145
13330
|
subscribers = new Set();
|
|
@@ -13256,7 +13441,8 @@ export function startUiServer({
|
|
|
13256
13441
|
return;
|
|
13257
13442
|
}
|
|
13258
13443
|
const { path: graphPath, graph } = readWorkspaceGraph(scoped.root);
|
|
13259
|
-
const
|
|
13444
|
+
const scopedUserCtx = workspaceScopedUserContext(scoped, userCtx);
|
|
13445
|
+
const hydratedGraph = hydrateWorkspaceGraphForRuntime(root, scoped, graph, scopedUserCtx);
|
|
13260
13446
|
const collaborationAccess = scoped.collaborationAccess || workspaceCollaborationAccess(null, userCtx.userId);
|
|
13261
13447
|
json(res, 200, {
|
|
13262
13448
|
ok: true,
|
|
@@ -13270,9 +13456,15 @@ export function startUiServer({
|
|
|
13270
13456
|
flowSource: scoped.flowSource,
|
|
13271
13457
|
archived: scoped.archived,
|
|
13272
13458
|
writable: !(scoped.archived || isReadonlyBuiltinFlowSource(scoped.flowSource))
|
|
13459
|
+
&& scoped.adminReadonly !== true
|
|
13273
13460
|
&& collaborationAccess.writable !== false,
|
|
13274
13461
|
collaboration: workspaceCollaborationSummaryWithUsers(scoped.collaboration, userCtx.userId),
|
|
13275
|
-
|
|
13462
|
+
adminReview: scoped.adminReadonly ? {
|
|
13463
|
+
readonly: true,
|
|
13464
|
+
ownerUserId: scoped.ownerUserId,
|
|
13465
|
+
ownerUsername: scoped.ownerUsername,
|
|
13466
|
+
} : null,
|
|
13467
|
+
workspaceSchedules: listWorkspaceScheduleStatusesForFlow(scopedUserCtx, scoped.flowSource || "user", scoped.flowId || ""),
|
|
13276
13468
|
});
|
|
13277
13469
|
} catch (e) {
|
|
13278
13470
|
json(res, 500, { error: (e && e.message) || String(e) });
|
|
@@ -13293,12 +13485,17 @@ export function startUiServer({
|
|
|
13293
13485
|
flowId: payload.flowId || "",
|
|
13294
13486
|
flowSource: payload.flowSource || "user",
|
|
13295
13487
|
workspaceId: payload.workspaceId || "",
|
|
13488
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
13296
13489
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
13297
13490
|
}, userCtx);
|
|
13298
13491
|
if (scoped.error) {
|
|
13299
13492
|
json(res, 400, { error: scoped.error });
|
|
13300
13493
|
return;
|
|
13301
13494
|
}
|
|
13495
|
+
if (scoped.adminReadonly) {
|
|
13496
|
+
json(res, 403, { error: "Admin Workspace review is read-only" });
|
|
13497
|
+
return;
|
|
13498
|
+
}
|
|
13302
13499
|
const { graph } = readWorkspaceGraph(scoped.root);
|
|
13303
13500
|
const nodeIds = normalizeDisplayShareNodeIds(payload.nodeIds, graph);
|
|
13304
13501
|
if (nodeIds.length === 0) {
|
|
@@ -13338,6 +13535,7 @@ export function startUiServer({
|
|
|
13338
13535
|
flowId: payload.flowId || "",
|
|
13339
13536
|
flowSource: payload.flowSource || "user",
|
|
13340
13537
|
workspaceId: payload.workspaceId || "",
|
|
13538
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
13341
13539
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
13342
13540
|
}, userCtx);
|
|
13343
13541
|
if (scoped.error) {
|
|
@@ -13451,8 +13649,21 @@ export function startUiServer({
|
|
|
13451
13649
|
json(res, 400, { error: "Missing flowId" });
|
|
13452
13650
|
return;
|
|
13453
13651
|
}
|
|
13652
|
+
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
13653
|
+
flowId,
|
|
13654
|
+
flowSource,
|
|
13655
|
+
archived: url.searchParams.get("archived") === "1",
|
|
13656
|
+
}, userCtx);
|
|
13657
|
+
if (scoped.error) {
|
|
13658
|
+
json(res, scoped.status || 400, { error: scoped.error });
|
|
13659
|
+
return;
|
|
13660
|
+
}
|
|
13454
13661
|
json(res, 200, {
|
|
13455
|
-
schedules: listWorkspaceScheduleStatusesForFlow(
|
|
13662
|
+
schedules: listWorkspaceScheduleStatusesForFlow(
|
|
13663
|
+
workspaceScopedUserContext(scoped, userCtx),
|
|
13664
|
+
flowSource,
|
|
13665
|
+
flowId,
|
|
13666
|
+
),
|
|
13456
13667
|
});
|
|
13457
13668
|
} catch (e) {
|
|
13458
13669
|
json(res, 500, { error: (e && e.message) || String(e) });
|
|
@@ -13473,12 +13684,17 @@ export function startUiServer({
|
|
|
13473
13684
|
flowId: payload.flowId || "",
|
|
13474
13685
|
flowSource: payload.flowSource || "user",
|
|
13475
13686
|
workspaceId: payload.workspaceId || "",
|
|
13687
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
13476
13688
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
13477
13689
|
}, userCtx);
|
|
13478
13690
|
if (scoped.error) {
|
|
13479
13691
|
json(res, 400, { error: scoped.error });
|
|
13480
13692
|
return;
|
|
13481
13693
|
}
|
|
13694
|
+
if (scoped.collaborationAccess?.runnable === false) {
|
|
13695
|
+
json(res, 403, { error: "Workspace run permission denied" });
|
|
13696
|
+
return;
|
|
13697
|
+
}
|
|
13482
13698
|
const flowId = String(payload.flowId || "").trim();
|
|
13483
13699
|
if (!flowId) {
|
|
13484
13700
|
json(res, 400, { error: "Missing flowId" });
|
|
@@ -13521,6 +13737,7 @@ export function startUiServer({
|
|
|
13521
13737
|
flowId: payload.flowId || "",
|
|
13522
13738
|
flowSource: payload.flowSource || "user",
|
|
13523
13739
|
workspaceId: payload.workspaceId || "",
|
|
13740
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
13524
13741
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
13525
13742
|
}, userCtx);
|
|
13526
13743
|
if (scoped.error) {
|
|
@@ -13585,6 +13802,7 @@ export function startUiServer({
|
|
|
13585
13802
|
flowId: payload.flowId || "",
|
|
13586
13803
|
flowSource: payload.flowSource || "user",
|
|
13587
13804
|
workspaceId: payload.workspaceId || "",
|
|
13805
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
13588
13806
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
13589
13807
|
}, userCtx);
|
|
13590
13808
|
if (scoped.error) {
|
|
@@ -13868,9 +14086,10 @@ export function startUiServer({
|
|
|
13868
14086
|
json(res, scoped.status || 400, { error: scoped.error });
|
|
13869
14087
|
return;
|
|
13870
14088
|
}
|
|
14089
|
+
const scopedUserCtx = workspaceScopedUserContext(scoped, userCtx);
|
|
13871
14090
|
json(res, 200, {
|
|
13872
14091
|
runs: listWorkspaceRunLogs({
|
|
13873
|
-
userId: flowSource === "workspace" ? "" :
|
|
14092
|
+
userId: flowSource === "workspace" ? "" : scopedUserCtx.userId || "",
|
|
13874
14093
|
flowId,
|
|
13875
14094
|
flowSource,
|
|
13876
14095
|
scheduleNodeId,
|
|
@@ -13902,8 +14121,9 @@ export function startUiServer({
|
|
|
13902
14121
|
json(res, scoped.status || 400, { error: scoped.error });
|
|
13903
14122
|
return;
|
|
13904
14123
|
}
|
|
14124
|
+
const scopedUserCtx = workspaceScopedUserContext(scoped, userCtx);
|
|
13905
14125
|
const run = listWorkspaceRunLogs({
|
|
13906
|
-
userId: flowSource === "workspace" ? "" :
|
|
14126
|
+
userId: flowSource === "workspace" ? "" : scopedUserCtx.userId || "",
|
|
13907
14127
|
flowId,
|
|
13908
14128
|
flowSource,
|
|
13909
14129
|
limit: 200,
|
|
@@ -13939,7 +14159,7 @@ export function startUiServer({
|
|
|
13939
14159
|
json(res, scoped.status || 400, { error: scoped.error });
|
|
13940
14160
|
return;
|
|
13941
14161
|
}
|
|
13942
|
-
const scopeKey = workspaceRunKey(userCtx, flowSource, flowId);
|
|
14162
|
+
const scopeKey = workspaceRunKey(workspaceScopedUserContext(scoped, userCtx), flowSource, flowId);
|
|
13943
14163
|
const entries = workspaceActiveRunsForScope(scopeKey).map(([, entry]) => entry);
|
|
13944
14164
|
const entry = entries[0] || null;
|
|
13945
14165
|
json(res, 200, {
|
|
@@ -13980,6 +14200,7 @@ export function startUiServer({
|
|
|
13980
14200
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
13981
14201
|
flowId,
|
|
13982
14202
|
flowSource,
|
|
14203
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
13983
14204
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
13984
14205
|
}, userCtx);
|
|
13985
14206
|
if (scoped.error) {
|
|
@@ -14124,6 +14345,7 @@ export function startUiServer({
|
|
|
14124
14345
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14125
14346
|
flowId: payload.flowId || "",
|
|
14126
14347
|
flowSource: payload.flowSource || "user",
|
|
14348
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
14127
14349
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
14128
14350
|
}, userCtx);
|
|
14129
14351
|
if (scoped.error) {
|
|
@@ -14185,6 +14407,7 @@ export function startUiServer({
|
|
|
14185
14407
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14186
14408
|
flowId: payload.flowId || "",
|
|
14187
14409
|
flowSource: payload.flowSource || "user",
|
|
14410
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
14188
14411
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
14189
14412
|
}, userCtx);
|
|
14190
14413
|
if (scoped.error) {
|
|
@@ -14259,6 +14482,7 @@ export function startUiServer({
|
|
|
14259
14482
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14260
14483
|
flowId: parsed.fields.flowId || "",
|
|
14261
14484
|
flowSource: parsed.fields.flowSource || "user",
|
|
14485
|
+
adminOwnerId: parsed.fields.adminOwnerId || "",
|
|
14262
14486
|
archived: parsed.fields.archived === "1" || parsed.fields.archived === "true" || parsed.fields.flowArchived === "true",
|
|
14263
14487
|
}, userCtx);
|
|
14264
14488
|
if (scoped.error) {
|
|
@@ -14304,6 +14528,7 @@ export function startUiServer({
|
|
|
14304
14528
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14305
14529
|
flowId: payload.flowId || "",
|
|
14306
14530
|
flowSource: payload.flowSource || "user",
|
|
14531
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
14307
14532
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
14308
14533
|
}, userCtx);
|
|
14309
14534
|
if (scoped.error) {
|
|
@@ -14344,6 +14569,7 @@ export function startUiServer({
|
|
|
14344
14569
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14345
14570
|
flowId: payload.flowId || "",
|
|
14346
14571
|
flowSource: payload.flowSource || "user",
|
|
14572
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
14347
14573
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
14348
14574
|
}, userCtx);
|
|
14349
14575
|
if (scoped.error) {
|
|
@@ -14394,6 +14620,7 @@ export function startUiServer({
|
|
|
14394
14620
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14395
14621
|
flowId: req.method === "POST" ? (payload.flowId || "") : (url.searchParams.get("flowId") || ""),
|
|
14396
14622
|
flowSource: req.method === "POST" ? (payload.flowSource || "user") : (url.searchParams.get("flowSource") || "user"),
|
|
14623
|
+
adminOwnerId: req.method === "POST" ? (payload.adminOwnerId || "") : "",
|
|
14397
14624
|
archived: req.method === "POST"
|
|
14398
14625
|
? (payload.archived === true || payload.flowArchived === true)
|
|
14399
14626
|
: (url.searchParams.get("archived") === "1" || url.searchParams.get("flowArchived") === "1"),
|
|
@@ -14435,6 +14662,7 @@ export function startUiServer({
|
|
|
14435
14662
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14436
14663
|
flowId: payload.flowId || "",
|
|
14437
14664
|
flowSource: payload.flowSource || "user",
|
|
14665
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
14438
14666
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
14439
14667
|
}, userCtx);
|
|
14440
14668
|
if (scoped.error) {
|
|
@@ -14525,6 +14753,7 @@ export function startUiServer({
|
|
|
14525
14753
|
const scoped = resolveWorkspaceScopeRoot(root, {
|
|
14526
14754
|
flowId: payload.flowId || "",
|
|
14527
14755
|
flowSource: payload.flowSource || "user",
|
|
14756
|
+
adminOwnerId: payload.adminOwnerId || "",
|
|
14528
14757
|
archived: payload.archived === true || payload.flowArchived === true,
|
|
14529
14758
|
}, userCtx);
|
|
14530
14759
|
if (scoped.error) {
|
|
@@ -15168,9 +15397,18 @@ export function startUiServer({
|
|
|
15168
15397
|
}
|
|
15169
15398
|
const nodesArchived = url.searchParams.get("archived") === "1";
|
|
15170
15399
|
try {
|
|
15400
|
+
const requestedContext = adminWorkspaceRequestedUserContext(userCtx);
|
|
15401
|
+
if (requestedContext.error) {
|
|
15402
|
+
json(res, requestedContext.status || 403, { error: requestedContext.error });
|
|
15403
|
+
return;
|
|
15404
|
+
}
|
|
15171
15405
|
const { setLanguage } = await import("./i18n.mjs");
|
|
15172
15406
|
setLanguage(lang);
|
|
15173
|
-
json(res, 200, listNodesJson(root, flowId || "", flowId ? flowSource : "", {
|
|
15407
|
+
json(res, 200, listNodesJson(root, flowId || "", flowId ? flowSource : "", {
|
|
15408
|
+
archived: nodesArchived,
|
|
15409
|
+
...requestedContext.userCtx,
|
|
15410
|
+
marketplaceScope,
|
|
15411
|
+
}));
|
|
15174
15412
|
} catch (e) {
|
|
15175
15413
|
json(res, 500, { error: (e && e.message) || String(e) });
|
|
15176
15414
|
}
|
|
@@ -15191,7 +15429,15 @@ export function startUiServer({
|
|
|
15191
15429
|
}
|
|
15192
15430
|
const archived = url.searchParams.get("archived") === "1";
|
|
15193
15431
|
try {
|
|
15194
|
-
const
|
|
15432
|
+
const requestedContext = adminWorkspaceRequestedUserContext(userCtx);
|
|
15433
|
+
if (requestedContext.error) {
|
|
15434
|
+
json(res, requestedContext.status || 403, { error: requestedContext.error });
|
|
15435
|
+
return;
|
|
15436
|
+
}
|
|
15437
|
+
const detail = readNodeDetailJson(root, nodeId, flowId, flowId ? (flowSource || "user") : "", {
|
|
15438
|
+
archived,
|
|
15439
|
+
...requestedContext.userCtx,
|
|
15440
|
+
});
|
|
15195
15441
|
if (detail.error) {
|
|
15196
15442
|
json(res, 404, { error: detail.error });
|
|
15197
15443
|
return;
|
|
@@ -15438,7 +15684,12 @@ export function startUiServer({
|
|
|
15438
15684
|
json(res, collaborationDenied.status, { error: collaborationDenied.error });
|
|
15439
15685
|
return;
|
|
15440
15686
|
}
|
|
15441
|
-
const
|
|
15687
|
+
const requestedContext = adminWorkspaceRequestedUserContext(userCtx);
|
|
15688
|
+
if (requestedContext.error) {
|
|
15689
|
+
json(res, requestedContext.status || 403, { error: requestedContext.error });
|
|
15690
|
+
return;
|
|
15691
|
+
}
|
|
15692
|
+
const result = readFlowJson(root, flowId, flowSource, { archived: flowArchived, ...requestedContext.userCtx });
|
|
15442
15693
|
if (result.error) {
|
|
15443
15694
|
json(res, 404, result);
|
|
15444
15695
|
return;
|