agentweaver 0.1.18 → 0.1.19
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/README.md +8 -0
- package/dist/index.js +6 -2
- package/dist/interactive/controller.js +74 -0
- package/dist/interactive/state.js +9 -0
- package/dist/interactive/web/index.js +149 -2
- package/dist/interactive/web/protocol.js +7 -1
- package/dist/interactive/web/server.js +439 -3
- package/dist/interactive/web/static/app.js +873 -2
- package/dist/interactive/web/static/index.html +37 -0
- package/dist/interactive/web/static/styles.css +1 -1
- package/dist/interactive/web/static/styles.input.css +380 -0
- package/dist/runtime/artifact-catalog.js +379 -0
- package/package.json +1 -1
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
connectionState: "connecting",
|
|
7
7
|
formValues: {},
|
|
8
8
|
modalSignature: null,
|
|
9
|
+
artifacts: {
|
|
10
|
+
signature: null,
|
|
11
|
+
loading: false,
|
|
12
|
+
catalog: null,
|
|
13
|
+
error: null,
|
|
14
|
+
preview: null,
|
|
15
|
+
selectedId: null,
|
|
16
|
+
actionStatus: null,
|
|
17
|
+
actionStatusFailed: false,
|
|
18
|
+
previewRequestId: 0,
|
|
19
|
+
viewerModes: {},
|
|
20
|
+
},
|
|
9
21
|
};
|
|
10
22
|
|
|
11
23
|
var elements = {
|
|
@@ -26,6 +38,22 @@
|
|
|
26
38
|
logTitle: document.getElementById("log-title"),
|
|
27
39
|
log: document.getElementById("log-text"),
|
|
28
40
|
clearLog: document.getElementById("clear-log-button"),
|
|
41
|
+
artifactOpen: document.getElementById("artifact-open-button"),
|
|
42
|
+
artifactDrawer: document.getElementById("artifact-drawer"),
|
|
43
|
+
artifactClose: document.getElementById("artifact-close-button"),
|
|
44
|
+
artifactTitle: document.getElementById("artifact-title"),
|
|
45
|
+
artifactMeta: document.getElementById("artifact-meta"),
|
|
46
|
+
artifactMessage: document.getElementById("artifact-message"),
|
|
47
|
+
artifactList: document.getElementById("artifact-list"),
|
|
48
|
+
artifactSelectedTitle: document.getElementById("artifact-selected-title"),
|
|
49
|
+
artifactSelectedMeta: document.getElementById("artifact-selected-meta"),
|
|
50
|
+
artifactActionStatus: document.getElementById("artifact-action-status"),
|
|
51
|
+
artifactCopyContent: document.getElementById("artifact-copy-content-button"),
|
|
52
|
+
artifactCopyReference: document.getElementById("artifact-copy-reference-button"),
|
|
53
|
+
artifactOpenRaw: document.getElementById("artifact-open-raw-link"),
|
|
54
|
+
artifactDownload: document.getElementById("artifact-download-link"),
|
|
55
|
+
artifactToolbarClose: document.getElementById("artifact-toolbar-close-button"),
|
|
56
|
+
artifactPreview: document.getElementById("artifact-preview-text"),
|
|
29
57
|
helpPanel: document.getElementById("help-panel"),
|
|
30
58
|
helpText: document.getElementById("help-text"),
|
|
31
59
|
closeHelp: document.getElementById("close-help-button"),
|
|
@@ -129,6 +157,12 @@
|
|
|
129
157
|
clearLog: function () {
|
|
130
158
|
api.send({ type: "log.clear" });
|
|
131
159
|
},
|
|
160
|
+
openArtifactExplorer: function () {
|
|
161
|
+
api.send({ type: "artifactExplorer.open" });
|
|
162
|
+
},
|
|
163
|
+
closeArtifactExplorer: function () {
|
|
164
|
+
api.send({ type: "artifactExplorer.close" });
|
|
165
|
+
},
|
|
132
166
|
toggleHelp: function () {
|
|
133
167
|
api.send({ type: "help.toggle", visible: !(state.viewModel && state.viewModel.helpVisible) });
|
|
134
168
|
},
|
|
@@ -205,6 +239,7 @@
|
|
|
205
239
|
|
|
206
240
|
renderFlows(vm);
|
|
207
241
|
renderModal(vm);
|
|
242
|
+
renderArtifactExplorer(vm);
|
|
208
243
|
}
|
|
209
244
|
|
|
210
245
|
function setTextPreservingScroll(element, value) {
|
|
@@ -335,6 +370,837 @@
|
|
|
335
370
|
});
|
|
336
371
|
}
|
|
337
372
|
|
|
373
|
+
function artifactState(vm) {
|
|
374
|
+
var explorer = vm && vm.artifactExplorer;
|
|
375
|
+
if (!explorer || typeof explorer !== "object") {
|
|
376
|
+
return {
|
|
377
|
+
available: false,
|
|
378
|
+
open: false,
|
|
379
|
+
scopeKey: null,
|
|
380
|
+
runId: null,
|
|
381
|
+
status: "unavailable",
|
|
382
|
+
label: "Artifact Explorer",
|
|
383
|
+
message: "",
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
return explorer;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function hasBlockingInput(vm) {
|
|
390
|
+
return Boolean(vm && (vm.confirmation || vm.confirmText || vm.form));
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function artifactSignature(explorer) {
|
|
394
|
+
return [
|
|
395
|
+
explorer.scopeKey || "",
|
|
396
|
+
explorer.runId || "",
|
|
397
|
+
Array.isArray(explorer.runIds) ? explorer.runIds.join(",") : "",
|
|
398
|
+
explorer.status || "",
|
|
399
|
+
typeof explorer.artifactCount === "number" ? String(explorer.artifactCount) : "",
|
|
400
|
+
].join("|");
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function renderArtifactExplorer(vm) {
|
|
404
|
+
var explorer = artifactState(vm);
|
|
405
|
+
var blocked = hasBlockingInput(vm);
|
|
406
|
+
elements.artifactOpen.hidden = !explorer.available || explorer.open || blocked;
|
|
407
|
+
elements.artifactOpen.textContent = explorer.label || "Artifacts";
|
|
408
|
+
elements.artifactDrawer.hidden = !explorer.open;
|
|
409
|
+
elements.artifactTitle.textContent = explorer.label || "Artifact Explorer";
|
|
410
|
+
elements.artifactMeta.textContent = artifactMetaText(explorer);
|
|
411
|
+
elements.artifactMessage.textContent = explorer.message || "";
|
|
412
|
+
|
|
413
|
+
if (!explorer.open) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
var signature = artifactSignature(explorer);
|
|
418
|
+
if (signature !== state.artifacts.signature) {
|
|
419
|
+
state.artifacts.signature = signature;
|
|
420
|
+
state.artifacts.loading = false;
|
|
421
|
+
state.artifacts.catalog = null;
|
|
422
|
+
state.artifacts.error = null;
|
|
423
|
+
state.artifacts.preview = null;
|
|
424
|
+
state.artifacts.selectedId = null;
|
|
425
|
+
state.artifacts.actionStatus = null;
|
|
426
|
+
state.artifacts.actionStatusFailed = false;
|
|
427
|
+
state.artifacts.previewRequestId += 1;
|
|
428
|
+
state.artifacts.viewerModes = {};
|
|
429
|
+
fetchArtifacts(explorer);
|
|
430
|
+
}
|
|
431
|
+
renderArtifactList(explorer);
|
|
432
|
+
renderArtifactPreview(explorer);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function artifactMetaText(explorer) {
|
|
436
|
+
var parts = [];
|
|
437
|
+
var count = typeof explorer.artifactCount === "number" ? explorer.artifactCount : null;
|
|
438
|
+
if (explorer.status === "completed") {
|
|
439
|
+
parts.push("Workflow completed. " + artifactCountText(count));
|
|
440
|
+
} else if (explorer.status === "failed") {
|
|
441
|
+
parts.push("Workflow failed. " + artifactCountText(count));
|
|
442
|
+
} else if (count !== null) {
|
|
443
|
+
parts.push(artifactCountText(count));
|
|
444
|
+
}
|
|
445
|
+
if (explorer.scopeKey) {
|
|
446
|
+
parts.push("Scope " + explorer.scopeKey);
|
|
447
|
+
}
|
|
448
|
+
if (Array.isArray(explorer.runIds) && explorer.runIds.length > 1) {
|
|
449
|
+
parts.push("Runs " + explorer.runIds.join(", "));
|
|
450
|
+
} else if (explorer.runId) {
|
|
451
|
+
parts.push("Run " + explorer.runId);
|
|
452
|
+
}
|
|
453
|
+
return parts.join(" | ");
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function artifactCountText(count) {
|
|
457
|
+
if (typeof count !== "number") {
|
|
458
|
+
return "Artifacts are available.";
|
|
459
|
+
}
|
|
460
|
+
return String(count) + " artifact" + (count === 1 ? "" : "s") + " created.";
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function artifactApiUrl(explorer, suffix) {
|
|
464
|
+
var base = "/__agentweaver/api/artifacts" + (suffix || "");
|
|
465
|
+
var params = new URLSearchParams();
|
|
466
|
+
if (explorer.scopeKey) {
|
|
467
|
+
params.set("scope", explorer.scopeKey);
|
|
468
|
+
}
|
|
469
|
+
if (Array.isArray(explorer.runIds) && explorer.runIds.length > 0) {
|
|
470
|
+
explorer.runIds.forEach(function (runId) {
|
|
471
|
+
params.append("runId", runId);
|
|
472
|
+
});
|
|
473
|
+
} else if (explorer.runId) {
|
|
474
|
+
params.set("runId", explorer.runId);
|
|
475
|
+
}
|
|
476
|
+
var query = params.toString();
|
|
477
|
+
return query ? base + "?" + query : base;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function artifactGroups(catalog) {
|
|
481
|
+
if (catalog && Array.isArray(catalog.groups) && catalog.groups.length > 0) {
|
|
482
|
+
return catalog.groups.map(function (group) {
|
|
483
|
+
return {
|
|
484
|
+
title: group.title || group.phaseId || "Artifacts",
|
|
485
|
+
items: Array.isArray(group.items) ? group.items : [],
|
|
486
|
+
};
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
return [{
|
|
490
|
+
title: "Artifacts",
|
|
491
|
+
items: catalog && Array.isArray(catalog.items) ? catalog.items : [],
|
|
492
|
+
}];
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function flattenArtifacts(catalog) {
|
|
496
|
+
return artifactGroups(catalog).reduce(function (items, group) {
|
|
497
|
+
return items.concat(group.items);
|
|
498
|
+
}, []);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function selectedArtifact() {
|
|
502
|
+
var items = state.artifacts.catalog ? flattenArtifacts(state.artifacts.catalog) : [];
|
|
503
|
+
return items.find(function (item) {
|
|
504
|
+
return item && item.id === state.artifacts.selectedId;
|
|
505
|
+
}) || null;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function artifactReference(item) {
|
|
509
|
+
return item && (item.relativePath || item.logicalKey || item.id) || "";
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function artifactDisplayTitle(item) {
|
|
513
|
+
return item && (item.title || item.logicalKey || item.relativePath || item.id) || "Untitled artifact";
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function formatArtifactBytes(value) {
|
|
517
|
+
if (!Number.isFinite(value)) {
|
|
518
|
+
return "Unknown size";
|
|
519
|
+
}
|
|
520
|
+
var bytes = Math.max(0, value);
|
|
521
|
+
if (bytes < 1024) {
|
|
522
|
+
return String(bytes) + " B";
|
|
523
|
+
}
|
|
524
|
+
var units = ["KB", "MB", "GB"];
|
|
525
|
+
var size = bytes / 1024;
|
|
526
|
+
var index = 0;
|
|
527
|
+
while (size >= 1024 && index < units.length - 1) {
|
|
528
|
+
size = size / 1024;
|
|
529
|
+
index += 1;
|
|
530
|
+
}
|
|
531
|
+
return (size >= 10 ? size.toFixed(0) : size.toFixed(1)).replace(/\.0$/, "") + " " + units[index];
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function artifactKind(item) {
|
|
535
|
+
return item && item.kind ? String(item.kind) : "unknown";
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function chooseDefaultArtifact(items) {
|
|
539
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
var best = null;
|
|
543
|
+
var bestScore = Infinity;
|
|
544
|
+
items.forEach(function (item, index) {
|
|
545
|
+
var score = artifactUsefulnessScore(item) * 1000 + index;
|
|
546
|
+
if (score < bestScore) {
|
|
547
|
+
best = item;
|
|
548
|
+
bestScore = score;
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
return best;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function artifactUsefulnessScore(item) {
|
|
555
|
+
var role = String(item && item.role || "").toLowerCase();
|
|
556
|
+
var haystack = [
|
|
557
|
+
item && item.logicalKey,
|
|
558
|
+
item && item.relativePath,
|
|
559
|
+
item && item.title,
|
|
560
|
+
item && item.id,
|
|
561
|
+
].filter(Boolean).join(" ").toLowerCase();
|
|
562
|
+
if (role.indexOf("design") !== -1 || /\bdesign\b/.test(haystack)) return 0;
|
|
563
|
+
if (role.indexOf("plan") !== -1 || /\bplan\b/.test(haystack)) return 1;
|
|
564
|
+
if (role.indexOf("review") !== -1 || /\breview\b/.test(haystack)) return 2;
|
|
565
|
+
if (role === "qa" || role.indexOf("qa") !== -1 || /\bqa\b/.test(haystack)) return 3;
|
|
566
|
+
if (role.indexOf("ready-to-merge") !== -1 || haystack.indexOf("ready-to-merge") !== -1) return 4;
|
|
567
|
+
if (isDiagnosticArtifact(role, haystack)) return 100;
|
|
568
|
+
return 50;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function isDiagnosticArtifact(role, haystack) {
|
|
572
|
+
return role.indexOf("diagnostic") !== -1
|
|
573
|
+
|| role.indexOf("internal") !== -1
|
|
574
|
+
|| /\b(log|trace|debug|diagnostic|diagnostics|internal)\b/.test(haystack)
|
|
575
|
+
|| haystack.indexOf("manifest-history") !== -1
|
|
576
|
+
|| haystack.indexOf("restart-archives") !== -1
|
|
577
|
+
|| haystack.indexOf("artifact-index") !== -1;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function fetchArtifacts(explorer) {
|
|
581
|
+
if (!explorer.scopeKey) {
|
|
582
|
+
state.artifacts.error = "Artifact scope is not available.";
|
|
583
|
+
renderArtifactList(explorer);
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
state.artifacts.loading = true;
|
|
587
|
+
renderArtifactList(explorer);
|
|
588
|
+
fetch(artifactApiUrl(explorer))
|
|
589
|
+
.then(function (response) {
|
|
590
|
+
return response.json().then(function (body) {
|
|
591
|
+
if (!response.ok) {
|
|
592
|
+
throw new Error(body && body.message ? body.message : "Artifact catalog request failed.");
|
|
593
|
+
}
|
|
594
|
+
return body;
|
|
595
|
+
});
|
|
596
|
+
})
|
|
597
|
+
.then(function (catalog) {
|
|
598
|
+
state.artifacts.catalog = catalog;
|
|
599
|
+
state.artifacts.error = null;
|
|
600
|
+
state.artifacts.loading = false;
|
|
601
|
+
var items = flattenArtifacts(catalog);
|
|
602
|
+
var selectedStillExists = items.some(function (item) {
|
|
603
|
+
return item && item.id === state.artifacts.selectedId;
|
|
604
|
+
});
|
|
605
|
+
if (!selectedStillExists) {
|
|
606
|
+
var defaultItem = chooseDefaultArtifact(items);
|
|
607
|
+
state.artifacts.selectedId = defaultItem ? defaultItem.id : null;
|
|
608
|
+
state.artifacts.preview = null;
|
|
609
|
+
if (defaultItem) {
|
|
610
|
+
previewArtifact(explorer, defaultItem);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
renderArtifactList(explorer);
|
|
614
|
+
renderArtifactPreview(explorer);
|
|
615
|
+
})
|
|
616
|
+
.catch(function (error) {
|
|
617
|
+
state.artifacts.catalog = null;
|
|
618
|
+
state.artifacts.error = error.message || "Artifact catalog request failed.";
|
|
619
|
+
state.artifacts.loading = false;
|
|
620
|
+
renderArtifactList(explorer);
|
|
621
|
+
renderArtifactPreview(explorer);
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function renderArtifactList(explorer) {
|
|
626
|
+
elements.artifactList.innerHTML = "";
|
|
627
|
+
if (state.artifacts.loading) {
|
|
628
|
+
elements.artifactList.append(artifactEmpty("Loading artifacts..."));
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (state.artifacts.error) {
|
|
632
|
+
elements.artifactList.append(artifactEmpty(state.artifacts.error));
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
var catalog = state.artifacts.catalog;
|
|
636
|
+
if (!catalog) {
|
|
637
|
+
elements.artifactList.append(artifactEmpty("Artifacts have not been loaded yet."));
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
var groups = artifactGroups(catalog);
|
|
641
|
+
var rendered = 0;
|
|
642
|
+
groups.forEach(function (group) {
|
|
643
|
+
var items = Array.isArray(group.items) ? group.items : [];
|
|
644
|
+
if (items.length === 0) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
var section = document.createElement("section");
|
|
648
|
+
section.className = "artifact-group";
|
|
649
|
+
var title = document.createElement("h3");
|
|
650
|
+
title.textContent = group.title || "Artifacts";
|
|
651
|
+
section.append(title);
|
|
652
|
+
items.forEach(function (item) {
|
|
653
|
+
rendered += 1;
|
|
654
|
+
section.append(renderArtifactRow(explorer, item));
|
|
655
|
+
});
|
|
656
|
+
elements.artifactList.append(section);
|
|
657
|
+
});
|
|
658
|
+
if (rendered === 0) {
|
|
659
|
+
elements.artifactList.append(artifactEmpty("No artifacts were found for the current scope or run."));
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function renderArtifactRow(explorer, item) {
|
|
664
|
+
var row = document.createElement("article");
|
|
665
|
+
row.className = "artifact-row" + (state.artifacts.selectedId === item.id ? " selected" : "");
|
|
666
|
+
row.dataset.artifactId = item.id || "";
|
|
667
|
+
var details = document.createElement("button");
|
|
668
|
+
details.type = "button";
|
|
669
|
+
details.className = "artifact-row-main";
|
|
670
|
+
details.setAttribute("aria-pressed", state.artifacts.selectedId === item.id ? "true" : "false");
|
|
671
|
+
details.addEventListener("click", function () {
|
|
672
|
+
previewArtifact(explorer, item);
|
|
673
|
+
});
|
|
674
|
+
var title = document.createElement("strong");
|
|
675
|
+
title.textContent = artifactDisplayTitle(item);
|
|
676
|
+
var meta = document.createElement("span");
|
|
677
|
+
meta.className = "artifact-row-meta";
|
|
678
|
+
var kind = document.createElement("span");
|
|
679
|
+
kind.textContent = artifactKind(item);
|
|
680
|
+
var size = document.createElement("span");
|
|
681
|
+
size.textContent = formatArtifactBytes(item.sizeBytes);
|
|
682
|
+
var reference = document.createElement("span");
|
|
683
|
+
reference.textContent = artifactReference(item);
|
|
684
|
+
meta.append(kind, size, reference);
|
|
685
|
+
details.append(title, meta);
|
|
686
|
+
|
|
687
|
+
var actions = document.createElement("div");
|
|
688
|
+
actions.className = "artifact-row-actions";
|
|
689
|
+
var raw = document.createElement("a");
|
|
690
|
+
raw.href = artifactApiUrl(explorer, "/" + encodeURIComponent(item.id) + "/raw");
|
|
691
|
+
raw.target = "_blank";
|
|
692
|
+
raw.rel = "noopener noreferrer";
|
|
693
|
+
raw.textContent = "Raw";
|
|
694
|
+
var download = document.createElement("a");
|
|
695
|
+
download.href = artifactApiUrl(explorer, "/" + encodeURIComponent(item.id) + "/download");
|
|
696
|
+
download.textContent = "Download";
|
|
697
|
+
actions.append(raw, download);
|
|
698
|
+
row.append(details, actions);
|
|
699
|
+
return row;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
function artifactEmpty(message) {
|
|
703
|
+
var empty = document.createElement("div");
|
|
704
|
+
empty.className = "artifact-empty";
|
|
705
|
+
empty.textContent = message;
|
|
706
|
+
return empty;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function previewArtifact(explorer, item) {
|
|
710
|
+
var requestId = state.artifacts.previewRequestId + 1;
|
|
711
|
+
state.artifacts.previewRequestId = requestId;
|
|
712
|
+
state.artifacts.selectedId = item.id;
|
|
713
|
+
state.artifacts.actionStatus = null;
|
|
714
|
+
state.artifacts.actionStatusFailed = false;
|
|
715
|
+
if (artifactKind(item) === "binary" || artifactKind(item) === "unknown") {
|
|
716
|
+
state.artifacts.preview = {
|
|
717
|
+
artifactId: item.id,
|
|
718
|
+
loading: false,
|
|
719
|
+
placeholder: true,
|
|
720
|
+
renderKind: artifactKind(item),
|
|
721
|
+
kind: artifactKind(item),
|
|
722
|
+
artifact: item,
|
|
723
|
+
sizeBytes: item.sizeBytes,
|
|
724
|
+
loadedBytes: 0,
|
|
725
|
+
content: "",
|
|
726
|
+
};
|
|
727
|
+
renderArtifactList(explorer);
|
|
728
|
+
renderArtifactPreview(explorer);
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
state.artifacts.preview = {
|
|
732
|
+
artifactId: item.id,
|
|
733
|
+
loading: true,
|
|
734
|
+
content: "Loading preview...",
|
|
735
|
+
renderKind: artifactKind(item),
|
|
736
|
+
kind: artifactKind(item),
|
|
737
|
+
artifact: item,
|
|
738
|
+
};
|
|
739
|
+
renderArtifactList(explorer);
|
|
740
|
+
renderArtifactPreview(explorer);
|
|
741
|
+
fetch(artifactApiUrl(explorer, "/" + encodeURIComponent(item.id) + "/preview"))
|
|
742
|
+
.then(function (response) {
|
|
743
|
+
return response.json().then(function (body) {
|
|
744
|
+
if (!response.ok) {
|
|
745
|
+
throw new Error(body && body.message ? body.message : "Artifact preview request failed.");
|
|
746
|
+
}
|
|
747
|
+
return body;
|
|
748
|
+
});
|
|
749
|
+
})
|
|
750
|
+
.then(function (preview) {
|
|
751
|
+
if (requestId !== state.artifacts.previewRequestId || state.artifacts.selectedId !== item.id) {
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
state.artifacts.preview = {
|
|
755
|
+
artifactId: item.id,
|
|
756
|
+
loading: false,
|
|
757
|
+
content: preview.content || "",
|
|
758
|
+
truncated: preview.truncated,
|
|
759
|
+
renderKind: preview.renderKind || preview.kind || artifactKind(item),
|
|
760
|
+
kind: preview.kind || preview.renderKind || artifactKind(item),
|
|
761
|
+
artifact: preview.artifact || item,
|
|
762
|
+
sizeBytes: Number.isFinite(preview.sizeBytes) ? preview.sizeBytes : item.sizeBytes,
|
|
763
|
+
loadedBytes: Number.isFinite(preview.loadedBytes) ? preview.loadedBytes : null,
|
|
764
|
+
jsonParseSafe: preview.jsonParseSafe,
|
|
765
|
+
title: preview.artifact && preview.artifact.title ? preview.artifact.title : item.title,
|
|
766
|
+
};
|
|
767
|
+
renderArtifactPreview(explorer);
|
|
768
|
+
})
|
|
769
|
+
.catch(function (error) {
|
|
770
|
+
if (requestId !== state.artifacts.previewRequestId || state.artifacts.selectedId !== item.id) {
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
state.artifacts.preview = {
|
|
774
|
+
artifactId: item.id,
|
|
775
|
+
loading: false,
|
|
776
|
+
content: error.message || "Artifact preview request failed.",
|
|
777
|
+
renderKind: artifactKind(item),
|
|
778
|
+
kind: artifactKind(item),
|
|
779
|
+
artifact: item,
|
|
780
|
+
error: true,
|
|
781
|
+
};
|
|
782
|
+
renderArtifactPreview(explorer);
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function renderArtifactPreview(explorer) {
|
|
787
|
+
var item = selectedArtifact();
|
|
788
|
+
renderArtifactToolbar(explorer, item);
|
|
789
|
+
var preview = state.artifacts.preview;
|
|
790
|
+
if (!item) {
|
|
791
|
+
elements.artifactSelectedTitle.textContent = "Preview";
|
|
792
|
+
elements.artifactSelectedMeta.textContent = "Select an artifact to preview it.";
|
|
793
|
+
renderPreviewMessage("Select an artifact to preview it.", false);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
elements.artifactSelectedTitle.textContent = artifactDisplayTitle(item);
|
|
797
|
+
elements.artifactSelectedMeta.textContent = [
|
|
798
|
+
artifactKind(item),
|
|
799
|
+
formatArtifactBytes(item.sizeBytes),
|
|
800
|
+
artifactReference(item),
|
|
801
|
+
].filter(Boolean).join(" | ");
|
|
802
|
+
if (!preview) {
|
|
803
|
+
renderPreviewMessage("Select an artifact to preview it.", false);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
renderArtifactPreviewContent(explorer, item, preview);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function resetPreviewContainer() {
|
|
810
|
+
elements.artifactPreview.textContent = "";
|
|
811
|
+
elements.artifactPreview.className = "artifact-preview-content text-panel compact";
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function renderPreviewMessage(message, failed) {
|
|
815
|
+
resetPreviewContainer();
|
|
816
|
+
elements.artifactPreview.classList.toggle("error-text", Boolean(failed));
|
|
817
|
+
elements.artifactPreview.textContent = message;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function renderArtifactPreviewContent(explorer, item, preview) {
|
|
821
|
+
if (preview.loading) {
|
|
822
|
+
renderPreviewMessage("Loading preview...", false);
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
if (preview.error) {
|
|
826
|
+
renderPreviewMessage(preview.content || "Artifact preview request failed.", true);
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
resetPreviewContainer();
|
|
831
|
+
var renderKind = String(preview.renderKind || preview.kind || artifactKind(item));
|
|
832
|
+
if (renderKind === "markdown") {
|
|
833
|
+
renderMarkdownPreview(elements.artifactPreview, preview);
|
|
834
|
+
} else if (renderKind === "json") {
|
|
835
|
+
renderJsonPreview(explorer, elements.artifactPreview, item, preview);
|
|
836
|
+
} else if (renderKind === "diff") {
|
|
837
|
+
renderTextPreview(elements.artifactPreview, preview, "Diff preview");
|
|
838
|
+
} else if (renderKind === "text") {
|
|
839
|
+
renderTextPreview(elements.artifactPreview, preview, "");
|
|
840
|
+
} else {
|
|
841
|
+
renderArtifactPlaceholder(explorer, elements.artifactPreview, item, preview);
|
|
842
|
+
}
|
|
843
|
+
renderTruncationStatus(elements.artifactPreview, preview);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function renderTextPreview(container, preview, label) {
|
|
847
|
+
if (label) {
|
|
848
|
+
var badge = document.createElement("div");
|
|
849
|
+
badge.className = "artifact-kind-label";
|
|
850
|
+
badge.textContent = label;
|
|
851
|
+
container.append(badge);
|
|
852
|
+
}
|
|
853
|
+
var block = document.createElement("pre");
|
|
854
|
+
block.className = "artifact-text-preview";
|
|
855
|
+
block.textContent = preview.content || "";
|
|
856
|
+
container.append(block);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function renderJsonPreview(explorer, container, item, preview) {
|
|
860
|
+
var viewer = document.createElement("div");
|
|
861
|
+
viewer.className = "artifact-json-viewer";
|
|
862
|
+
var controls = document.createElement("div");
|
|
863
|
+
controls.className = "artifact-preview-modes";
|
|
864
|
+
var artifactId = item.id || "";
|
|
865
|
+
var mode = state.artifacts.viewerModes[artifactId] || "pretty";
|
|
866
|
+
["pretty", "raw"].forEach(function (nextMode) {
|
|
867
|
+
var button = document.createElement("button");
|
|
868
|
+
button.type = "button";
|
|
869
|
+
button.textContent = nextMode === "pretty" ? "Pretty" : "Raw";
|
|
870
|
+
button.className = mode === nextMode ? "primary" : "";
|
|
871
|
+
button.setAttribute("aria-pressed", mode === nextMode ? "true" : "false");
|
|
872
|
+
button.addEventListener("click", function () {
|
|
873
|
+
state.artifacts.viewerModes[artifactId] = nextMode;
|
|
874
|
+
renderArtifactPreview(explorer);
|
|
875
|
+
});
|
|
876
|
+
controls.append(button);
|
|
877
|
+
});
|
|
878
|
+
viewer.append(controls);
|
|
879
|
+
|
|
880
|
+
var block = document.createElement("pre");
|
|
881
|
+
block.className = "artifact-text-preview artifact-json-preview";
|
|
882
|
+
var raw = preview.content || "";
|
|
883
|
+
if (mode === "raw") {
|
|
884
|
+
block.textContent = raw;
|
|
885
|
+
viewer.append(block);
|
|
886
|
+
container.append(viewer);
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (preview.truncated || preview.jsonParseSafe === false) {
|
|
891
|
+
viewer.append(previewWarning("JSON Pretty is unavailable for truncated or unsafe previews. Raw preview is shown."));
|
|
892
|
+
block.textContent = raw;
|
|
893
|
+
viewer.append(block);
|
|
894
|
+
container.append(viewer);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
try {
|
|
899
|
+
block.textContent = JSON.stringify(JSON.parse(raw), null, 2);
|
|
900
|
+
} catch (error) {
|
|
901
|
+
viewer.append(previewWarning("JSON parse error: " + (error && error.message ? error.message : "invalid JSON.")));
|
|
902
|
+
block.textContent = raw;
|
|
903
|
+
}
|
|
904
|
+
viewer.append(block);
|
|
905
|
+
container.append(viewer);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function previewWarning(message) {
|
|
909
|
+
var warning = document.createElement("div");
|
|
910
|
+
warning.className = "artifact-preview-warning";
|
|
911
|
+
warning.textContent = message;
|
|
912
|
+
return warning;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function renderArtifactPlaceholder(explorer, container, item, preview) {
|
|
916
|
+
var panel = document.createElement("div");
|
|
917
|
+
panel.className = "artifact-placeholder";
|
|
918
|
+
var title = document.createElement("strong");
|
|
919
|
+
title.textContent = artifactKind(item) === "binary" ? "Binary artifact" : "Preview unavailable";
|
|
920
|
+
var meta = document.createElement("dl");
|
|
921
|
+
appendPlaceholderMeta(meta, "Kind", artifactKind(item));
|
|
922
|
+
appendPlaceholderMeta(meta, "Path", artifactReference(item) || item.id || "Unknown");
|
|
923
|
+
appendPlaceholderMeta(meta, "Size", formatArtifactBytes(Number.isFinite(preview.sizeBytes) ? preview.sizeBytes : item.sizeBytes));
|
|
924
|
+
var actions = document.createElement("div");
|
|
925
|
+
actions.className = "artifact-placeholder-actions";
|
|
926
|
+
var raw = document.createElement("a");
|
|
927
|
+
raw.href = artifactApiUrl(explorer, "/" + encodeURIComponent(item.id) + "/raw");
|
|
928
|
+
raw.target = "_blank";
|
|
929
|
+
raw.rel = "noopener noreferrer";
|
|
930
|
+
raw.textContent = "Open raw";
|
|
931
|
+
var download = document.createElement("a");
|
|
932
|
+
download.href = artifactApiUrl(explorer, "/" + encodeURIComponent(item.id) + "/download");
|
|
933
|
+
download.textContent = "Download";
|
|
934
|
+
actions.append(raw, download);
|
|
935
|
+
panel.append(title, meta, actions);
|
|
936
|
+
container.append(panel);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
function appendPlaceholderMeta(list, label, value) {
|
|
940
|
+
var term = document.createElement("dt");
|
|
941
|
+
term.textContent = label;
|
|
942
|
+
var detail = document.createElement("dd");
|
|
943
|
+
detail.textContent = value || "";
|
|
944
|
+
list.append(term, detail);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
function renderTruncationStatus(container, preview) {
|
|
948
|
+
if (!preview.truncated) {
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
var status = document.createElement("div");
|
|
952
|
+
status.className = "artifact-truncation";
|
|
953
|
+
var loaded = Number.isFinite(preview.loadedBytes) ? preview.loadedBytes : 0;
|
|
954
|
+
var total = Number.isFinite(preview.sizeBytes) ? preview.sizeBytes : loaded;
|
|
955
|
+
status.textContent = "Preview truncated: loaded " + formatArtifactBytes(loaded) + " of " + formatArtifactBytes(total) + ".";
|
|
956
|
+
container.append(status);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function renderMarkdownPreview(container, preview) {
|
|
960
|
+
var root = document.createElement("div");
|
|
961
|
+
root.className = "artifact-rendered-markdown";
|
|
962
|
+
appendMarkdownBlocks(root, preview.content || "");
|
|
963
|
+
container.append(root);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
function appendMarkdownBlocks(container, markdown) {
|
|
967
|
+
var lines = String(markdown || "").replace(/\r\n?/g, "\n").split("\n");
|
|
968
|
+
var index = 0;
|
|
969
|
+
while (index < lines.length) {
|
|
970
|
+
var line = lines[index];
|
|
971
|
+
if (!line.trim()) {
|
|
972
|
+
index += 1;
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
var fence = line.match(/^\s*(```+|~~~+)\s*([^\s`]*)\s*$/);
|
|
977
|
+
if (fence) {
|
|
978
|
+
var marker = fence[1];
|
|
979
|
+
var codeLines = [];
|
|
980
|
+
index += 1;
|
|
981
|
+
while (index < lines.length && lines[index].trim() !== marker) {
|
|
982
|
+
codeLines.push(lines[index]);
|
|
983
|
+
index += 1;
|
|
984
|
+
}
|
|
985
|
+
if (index < lines.length) index += 1;
|
|
986
|
+
var pre = document.createElement("pre");
|
|
987
|
+
var code = document.createElement("code");
|
|
988
|
+
if (fence[2]) {
|
|
989
|
+
code.dataset.language = fence[2];
|
|
990
|
+
}
|
|
991
|
+
code.textContent = codeLines.join("\n");
|
|
992
|
+
pre.append(code);
|
|
993
|
+
container.append(pre);
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
if (isMarkdownTable(lines, index)) {
|
|
998
|
+
var tableResult = renderMarkdownTable(lines, index);
|
|
999
|
+
container.append(tableResult.table);
|
|
1000
|
+
index = tableResult.nextIndex;
|
|
1001
|
+
continue;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
var heading = line.match(/^\s{0,3}(#{1,6})\s+(.+?)\s*#*\s*$/);
|
|
1005
|
+
if (heading) {
|
|
1006
|
+
var headingNode = document.createElement("h" + heading[1].length);
|
|
1007
|
+
appendInlineMarkdown(headingNode, heading[2]);
|
|
1008
|
+
container.append(headingNode);
|
|
1009
|
+
index += 1;
|
|
1010
|
+
continue;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
var listMatch = line.match(/^\s{0,3}((?:[-*+])|(?:\d+[.)]))\s+(.+)$/);
|
|
1014
|
+
if (listMatch) {
|
|
1015
|
+
var ordered = /\d/.test(listMatch[1]);
|
|
1016
|
+
var list = document.createElement(ordered ? "ol" : "ul");
|
|
1017
|
+
while (index < lines.length) {
|
|
1018
|
+
var current = lines[index].match(/^\s{0,3}((?:[-*+])|(?:\d+[.)]))\s+(.+)$/);
|
|
1019
|
+
if (!current || /\d/.test(current[1]) !== ordered) {
|
|
1020
|
+
break;
|
|
1021
|
+
}
|
|
1022
|
+
var item = document.createElement("li");
|
|
1023
|
+
appendInlineMarkdown(item, current[2]);
|
|
1024
|
+
list.append(item);
|
|
1025
|
+
index += 1;
|
|
1026
|
+
}
|
|
1027
|
+
container.append(list);
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
var paragraphLines = [line.trim()];
|
|
1032
|
+
index += 1;
|
|
1033
|
+
while (index < lines.length && lines[index].trim() && !isMarkdownBlockStart(lines, index)) {
|
|
1034
|
+
paragraphLines.push(lines[index].trim());
|
|
1035
|
+
index += 1;
|
|
1036
|
+
}
|
|
1037
|
+
var paragraph = document.createElement("p");
|
|
1038
|
+
appendInlineMarkdown(paragraph, paragraphLines.join(" "));
|
|
1039
|
+
container.append(paragraph);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
function isMarkdownBlockStart(lines, index) {
|
|
1044
|
+
var line = lines[index] || "";
|
|
1045
|
+
return /^\s*(```+|~~~+)/.test(line)
|
|
1046
|
+
|| /^\s{0,3}#{1,6}\s+/.test(line)
|
|
1047
|
+
|| /^\s{0,3}((?:[-*+])|(?:\d+[.)]))\s+/.test(line)
|
|
1048
|
+
|| isMarkdownTable(lines, index);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
function isMarkdownTable(lines, index) {
|
|
1052
|
+
return index + 1 < lines.length
|
|
1053
|
+
&& lines[index].indexOf("|") !== -1
|
|
1054
|
+
&& /^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(lines[index + 1] || "");
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function splitMarkdownTableRow(line) {
|
|
1058
|
+
var value = String(line || "").trim();
|
|
1059
|
+
if (value.charAt(0) === "|") value = value.slice(1);
|
|
1060
|
+
if (value.charAt(value.length - 1) === "|") value = value.slice(0, -1);
|
|
1061
|
+
return value.split("|").map(function (cell) {
|
|
1062
|
+
return cell.trim();
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
function renderMarkdownTable(lines, startIndex) {
|
|
1067
|
+
var table = document.createElement("table");
|
|
1068
|
+
var thead = document.createElement("thead");
|
|
1069
|
+
var tbody = document.createElement("tbody");
|
|
1070
|
+
var headerRow = document.createElement("tr");
|
|
1071
|
+
splitMarkdownTableRow(lines[startIndex]).forEach(function (cell) {
|
|
1072
|
+
var th = document.createElement("th");
|
|
1073
|
+
appendInlineMarkdown(th, cell);
|
|
1074
|
+
headerRow.append(th);
|
|
1075
|
+
});
|
|
1076
|
+
thead.append(headerRow);
|
|
1077
|
+
var index = startIndex + 2;
|
|
1078
|
+
while (index < lines.length && lines[index].indexOf("|") !== -1 && lines[index].trim()) {
|
|
1079
|
+
var row = document.createElement("tr");
|
|
1080
|
+
splitMarkdownTableRow(lines[index]).forEach(function (cell) {
|
|
1081
|
+
var td = document.createElement("td");
|
|
1082
|
+
appendInlineMarkdown(td, cell);
|
|
1083
|
+
row.append(td);
|
|
1084
|
+
});
|
|
1085
|
+
tbody.append(row);
|
|
1086
|
+
index += 1;
|
|
1087
|
+
}
|
|
1088
|
+
table.append(thead, tbody);
|
|
1089
|
+
return { table: table, nextIndex: index };
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
function appendInlineMarkdown(parent, value) {
|
|
1093
|
+
var source = String(value || "");
|
|
1094
|
+
var pattern = /(`[^`]+`)|(\[([^\]]+)\]\(([^)\s]+)\))/g;
|
|
1095
|
+
var cursor = 0;
|
|
1096
|
+
var match;
|
|
1097
|
+
while ((match = pattern.exec(source))) {
|
|
1098
|
+
if (match.index > cursor) {
|
|
1099
|
+
parent.append(document.createTextNode(source.slice(cursor, match.index)));
|
|
1100
|
+
}
|
|
1101
|
+
if (match[1]) {
|
|
1102
|
+
var code = document.createElement("code");
|
|
1103
|
+
code.textContent = match[1].slice(1, -1);
|
|
1104
|
+
parent.append(code);
|
|
1105
|
+
} else {
|
|
1106
|
+
var href = safeMarkdownHref(match[4]);
|
|
1107
|
+
if (href) {
|
|
1108
|
+
var link = document.createElement("a");
|
|
1109
|
+
link.href = href;
|
|
1110
|
+
link.target = "_blank";
|
|
1111
|
+
link.rel = "noopener noreferrer";
|
|
1112
|
+
link.textContent = match[3];
|
|
1113
|
+
parent.append(link);
|
|
1114
|
+
} else {
|
|
1115
|
+
parent.append(document.createTextNode(match[0]));
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
cursor = pattern.lastIndex;
|
|
1119
|
+
}
|
|
1120
|
+
if (cursor < source.length) {
|
|
1121
|
+
parent.append(document.createTextNode(source.slice(cursor)));
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
function safeMarkdownHref(value) {
|
|
1126
|
+
var raw = String(value || "").trim();
|
|
1127
|
+
try {
|
|
1128
|
+
var parsed = new URL(raw, window.location.href);
|
|
1129
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:" || parsed.protocol === "mailto:") {
|
|
1130
|
+
return parsed.href;
|
|
1131
|
+
}
|
|
1132
|
+
} catch {
|
|
1133
|
+
return null;
|
|
1134
|
+
}
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
function renderArtifactToolbar(explorer, item) {
|
|
1139
|
+
var preview = state.artifacts.preview;
|
|
1140
|
+
var hasItem = Boolean(item);
|
|
1141
|
+
var hasContent = hasItem && preview && !preview.loading && !preview.error && typeof preview.content === "string";
|
|
1142
|
+
elements.artifactCopyContent.disabled = !hasContent;
|
|
1143
|
+
elements.artifactCopyReference.disabled = !hasItem;
|
|
1144
|
+
setArtifactActionLink(elements.artifactOpenRaw, hasItem ? artifactApiUrl(explorer, "/" + encodeURIComponent(item.id) + "/raw") : "");
|
|
1145
|
+
setArtifactActionLink(elements.artifactDownload, hasItem ? artifactApiUrl(explorer, "/" + encodeURIComponent(item.id) + "/download") : "");
|
|
1146
|
+
elements.artifactActionStatus.textContent = state.artifacts.actionStatus || "";
|
|
1147
|
+
elements.artifactActionStatus.classList.toggle("error-text", Boolean(state.artifacts.actionStatusFailed));
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
function setArtifactActionLink(link, href) {
|
|
1151
|
+
if (href) {
|
|
1152
|
+
link.href = href;
|
|
1153
|
+
link.classList.remove("disabled");
|
|
1154
|
+
link.setAttribute("aria-disabled", "false");
|
|
1155
|
+
} else {
|
|
1156
|
+
link.removeAttribute("href");
|
|
1157
|
+
link.classList.add("disabled");
|
|
1158
|
+
link.setAttribute("aria-disabled", "true");
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
function setArtifactActionStatus(message, failed) {
|
|
1163
|
+
state.artifacts.actionStatus = message;
|
|
1164
|
+
state.artifacts.actionStatusFailed = Boolean(failed);
|
|
1165
|
+
elements.artifactActionStatus.textContent = message || "";
|
|
1166
|
+
elements.artifactActionStatus.classList.toggle("error-text", Boolean(failed));
|
|
1167
|
+
if (failed && message) {
|
|
1168
|
+
appendLog("[artifacts] " + message);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
function writeClipboard(value, successMessage) {
|
|
1173
|
+
if (typeof navigator === "undefined" || !navigator.clipboard || typeof navigator.clipboard.writeText !== "function") {
|
|
1174
|
+
setArtifactActionStatus("Clipboard is not available in this browser.", true);
|
|
1175
|
+
return Promise.resolve(false);
|
|
1176
|
+
}
|
|
1177
|
+
return navigator.clipboard.writeText(value).then(function () {
|
|
1178
|
+
setArtifactActionStatus(successMessage, false);
|
|
1179
|
+
return true;
|
|
1180
|
+
}).catch(function (error) {
|
|
1181
|
+
setArtifactActionStatus("Clipboard copy failed: " + (error && error.message ? error.message : "permission denied."), true);
|
|
1182
|
+
return false;
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
function copySelectedArtifactContent() {
|
|
1187
|
+
var preview = state.artifacts.preview;
|
|
1188
|
+
if (!preview || preview.loading || preview.error || typeof preview.content !== "string") {
|
|
1189
|
+
setArtifactActionStatus("Preview content is not ready to copy.", true);
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
writeClipboard(preview.content, "Copied artifact preview content.");
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
function copySelectedArtifactReference() {
|
|
1196
|
+
var item = selectedArtifact();
|
|
1197
|
+
if (!item) {
|
|
1198
|
+
setArtifactActionStatus("No artifact is selected.", true);
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
writeClipboard(artifactReference(item), "Copied artifact path/reference.");
|
|
1202
|
+
}
|
|
1203
|
+
|
|
338
1204
|
function renderModal(vm) {
|
|
339
1205
|
var nextSignature = modalSignature(vm);
|
|
340
1206
|
if (state.modalSignature === nextSignature) {
|
|
@@ -383,7 +1249,7 @@
|
|
|
383
1249
|
type: "form",
|
|
384
1250
|
formId: vm.form.formId,
|
|
385
1251
|
title: vm.form.title || definition.title,
|
|
386
|
-
|
|
1252
|
+
description: definition.description || "",
|
|
387
1253
|
footer: vm.form.footer,
|
|
388
1254
|
error: vm.form.error,
|
|
389
1255
|
submitLabel: definition.submitLabel,
|
|
@@ -465,7 +1331,7 @@
|
|
|
465
1331
|
|
|
466
1332
|
function renderForm(formModel) {
|
|
467
1333
|
var definition = formModel.definition || {};
|
|
468
|
-
var modal = createModal(text(formModel.title || definition.title, "Input required"), text(definition.description
|
|
1334
|
+
var modal = createModal(text(formModel.title || definition.title, "Input required"), text(definition.description, ""));
|
|
469
1335
|
modal.classList.add("form-" + classNameToken(formModel.formId || definition.formId || "unknown"));
|
|
470
1336
|
var body = modal.querySelector(".modal-body");
|
|
471
1337
|
var footerNote = modal.querySelector(".modal-note");
|
|
@@ -687,6 +1553,11 @@
|
|
|
687
1553
|
|
|
688
1554
|
elements.run.addEventListener("click", api.openRunConfirm);
|
|
689
1555
|
elements.interrupt.addEventListener("click", api.openInterruptConfirm);
|
|
1556
|
+
elements.artifactOpen.addEventListener("click", api.openArtifactExplorer);
|
|
1557
|
+
elements.artifactClose.addEventListener("click", api.closeArtifactExplorer);
|
|
1558
|
+
elements.artifactToolbarClose.addEventListener("click", api.closeArtifactExplorer);
|
|
1559
|
+
elements.artifactCopyContent.addEventListener("click", copySelectedArtifactContent);
|
|
1560
|
+
elements.artifactCopyReference.addEventListener("click", copySelectedArtifactReference);
|
|
690
1561
|
elements.help.addEventListener("click", api.toggleHelp);
|
|
691
1562
|
elements.closeHelp.addEventListener("click", function () {
|
|
692
1563
|
api.showHelp(false);
|