@unofficialbox/box-open-elements 0.20.0 → 0.22.0
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/dist/components/actions/menu-item.d.ts +2 -0
- package/dist/components/actions/menu-item.js +4 -0
- package/dist/components/collections/card.js +6 -0
- package/dist/components/collections/result-blocks.js +4 -1
- package/dist/components/feedback/alert.d.ts +2 -0
- package/dist/components/feedback/alert.js +17 -13
- package/dist/components/feedback/toast.d.ts +10 -1
- package/dist/components/feedback/toast.js +69 -27
- package/dist/components/forms/number-input.d.ts +1 -0
- package/dist/components/forms/number-input.js +9 -6
- package/dist/components/forms/search-field.js +16 -0
- package/dist/components/overlays/context-menu.d.ts +2 -0
- package/dist/components/overlays/context-menu.js +7 -0
- package/dist/components/overlays/dialog.js +19 -3
- package/dist/components/overlays/popover.js +6 -1
- package/dist/element-maps.d.ts +11 -1
- package/dist/foundations/a11y/announcer.d.ts +12 -0
- package/dist/foundations/a11y/announcer.js +75 -0
- package/dist/foundations/a11y/focus.js +46 -25
- package/dist/foundations/a11y/index.d.ts +2 -0
- package/dist/foundations/a11y/index.js +1 -0
- package/dist/foundations/icons/box-iconography.d.ts +472 -472
- package/dist/foundations/icons/box-iconography.generated.d.ts +1151 -679
- package/dist/foundations/icons/box-iconography.generated.js +1006 -3588
- package/dist/foundations/icons/glyphs/index.d.ts +1 -0
- package/dist/foundations/icons/glyphs/index.js +2 -0
- package/dist/foundations/icons/glyphs/package.json +1 -0
- package/dist/foundations/overlay/positioning.js +7 -0
- package/dist/foundations/status/index.d.ts +1 -1
- package/dist/foundations/status/index.js +8 -6
- package/dist/foundations/tokens/box-dark.js +4 -1
- package/dist/foundations/tokens/box-defaults.js +3 -0
- package/dist/foundations/tokens/registry.d.ts +3 -0
- package/dist/foundations/tokens/registry.js +3 -0
- package/dist/foundations/tokens/types.d.ts +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/patterns/agent-chat/agent-chat.js +12 -4
- package/dist/patterns/call-console/call-console.d.ts +3 -0
- package/dist/patterns/call-console/call-console.js +114 -20
- package/dist/patterns/content-explorer/adapters/action-menu.js +7 -5
- package/dist/patterns/content-explorer/adapters/toolbar.js +6 -2
- package/dist/patterns/file-request/file-request-builder.js +3 -0
- package/dist/patterns/flow-builder/flow-builder.d.ts +79 -0
- package/dist/patterns/flow-builder/flow-builder.js +243 -0
- package/dist/patterns/flow-builder/index.d.ts +3 -0
- package/dist/patterns/flow-builder/index.js +3 -0
- package/dist/patterns/flow-builder/model.d.ts +81 -0
- package/dist/patterns/flow-builder/model.js +40 -0
- package/dist/patterns/flow-builder/primitives.d.ts +57 -0
- package/dist/patterns/flow-builder/primitives.js +256 -0
- package/dist/patterns/lineage/lineage-graph.js +26 -6
- package/dist/patterns/notifications/notification-inbox.js +19 -3
- package/dist/patterns/preview/annotation-inspector.js +2 -2
- package/dist/patterns/undo/index.d.ts +19 -0
- package/dist/patterns/undo/index.js +106 -0
- package/package.json +11 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { icon2Chat, icon2ChatQuestion, icon2OverlaySquares, icon3OverlaySquares, icon3SquareCircle, icon3Tier, icon4Squares, icon4Squares2, icon6Dots, iconAddSmall, iconAddSquares, iconAddToCart, iconAid, iconAppCloud, iconArrowDown, iconArrowRight, iconAttachment, iconAudio, iconAward, iconBadge, iconBag, iconBank, iconBattery, iconBell, iconBinders, iconBolt, iconBoltBubble, iconBrain, iconBriefcase, iconBroadcast, iconBrowser, iconBrush, iconCalendar, iconCalendar2, iconCalendarAdded, iconCart, iconCart2, iconCash, iconCautionFile, iconCautionPhone, iconCautionTriangle, iconCenter, iconChatBubble, iconChatQuestion, iconCheck, iconCheckmark, iconClipboard, iconClock1, iconClock2, iconClock3, iconCloud, iconCloudServer, iconCode, iconCodeBrowser, iconCompass, iconComputer, iconComputerBadge, iconComputerDownload, iconComputerUpoad, iconConnectedDots, iconConnectedTogether, iconContainerLines, iconContainerLines2, iconCubeDotLine, iconCubeLine, iconCycle, iconDesktopLaptop, iconDevices, iconDistribute, iconDistribute2, iconDna, iconDollarSign, iconDonutCoffee, iconDownload, iconDrop, iconEnterpriseBuilding, iconEnvelope, iconEnvelopeBug, iconEnvelopeDoc, iconEnvelopeShred, iconExclamationMark, iconEye, iconFileApproved, iconFileBlank, iconFileBug, iconFileCheck, iconFileCloud, iconFileCopy, iconFileDocument, iconFileImage, iconFileInfographic, iconFileInsights, iconFileMove, iconFileMusic, iconFilePlus, iconFilePresentations, iconFileSpeed, iconFileSpreadsheet, iconFileText, iconFileVideo, iconFingerPrint, iconFlight, iconFolder, iconFolderUp, iconFolderUpload, iconFtpFolder, iconFunnel, iconGear, iconGears, iconGraduationCap, iconGraphIncrease, iconGraphMeasure, iconGroupCall, iconHeart, iconHome, iconImage, iconKeySafe, iconLeavesGrowing, iconLight, iconLineGraphV2, iconLineGraph, iconLink, iconLock, iconMagnifyingGlass, iconMartini, iconMaze, iconMedTool, iconMegaphone, iconMetadata, iconMicrophone, iconMinus, iconMixedMediaDownload, iconMusicNote, iconNotePad, iconNumber0, iconNumber1, iconNumber2, iconNumber3, iconNumber4, iconNumber5, iconNumber6, iconNumber7, iconNumber8, iconNumber9, iconOMaru, iconOverlay, iconPaper, iconPen, iconPerson, iconPhone, iconPhone2, iconPhoneBrowser, iconPieChart, iconPieChart3, iconPin, iconPin2, iconPlane, iconPlay, iconPlus, iconPodium, iconPoint, iconPointCenter, iconQuestionMark, iconRaft, iconRetailTag, iconRightToForget, iconRing, iconRocket, iconScale, iconScale2, iconScan, iconServer, iconShakeLove, iconSharedUsers, iconShield2Tone, iconShieldCheck, iconShieldVarified, iconSlice, iconSlider, iconSmbBuilding, iconSolidArrowDown, iconSolidArrowRight, iconSolidCheck, iconSolidCheckmark, iconSolidClock1, iconSolidClock2, iconSolidCompass, iconSolidDollarSign, iconSolidExclamationMark, iconSolidMinus, iconSolidOMaru, iconSolidPlay, iconSolidPlus, iconSolidQuestionMark, iconSolidXBatsu, iconSpeachBubble, iconSpotlight, iconSprayBottle, iconSquaresScale, iconSquaresScaleTop, iconSquaresTogether, iconStar, iconStopHand, iconStorage, iconStorageCloud, iconStorageKey, iconSun, iconTarget, iconTeam, iconTeamAdd, iconThumb, iconToggle, iconTools, iconTrophy, iconTruck, iconTwoFiles, iconTyping, iconTypingNow, iconUpDown, iconUpload, iconUploadCloud, iconUsb, iconUserAlert, iconUserVerified, iconUserVerifiedUnknown, iconUserBadge, iconUserPrimary, iconUserTimed, iconVideo, iconVideoCamera, iconVideoCamera2, iconWriting, iconXBatsu, iconZones, icon2Chat2, icon2ChatQuestion2, icon2OverlaySquares2, icon3OverlaySquares2, icon3SquareCircle2, icon3Tier2, icon4Squares3, icon4Squares1, icon6Dots2, iconAddSmall2, iconAddSquares2, iconAddToCart2, iconAid2, iconAppCloud2, iconArrowDown2, iconArrowRight2, iconAttachment2, iconAudio2, iconAward2, iconBadge2, iconBag2, iconBank2, iconBattery2, iconBell2, iconBinders2, iconBolt2, iconBoltBubble2, iconBrain2, iconBriefcase2, iconBroadcast2, iconBrowser2, iconBrush2, iconCalendar3, iconCalendar1, iconCalendarAdded2, iconCart3, iconCart1, iconCash2, iconCautionFile2, iconCautionPhone2, iconCautionTriangle2, iconCenter2, iconChatBubble2, iconChatQuestion2, iconCheck2, iconCheckmark2, iconClipboard2, iconClock12, iconClock22, iconClock32, iconCloud2, iconCloudServer2, iconCode2, iconCodeBrowser2, iconCompass2, iconComputer2, iconComputerBadge2, iconComputerDownload2, iconComputerUpoad2, iconConnectedDots2, iconConnectedTogether2, iconContainerLines3, iconContainerLines22, iconCubeDotLine2, iconCubeLine2, iconCycle2, iconDesktopLaptop2, iconDevices2, iconDistribute3, iconDistribute1, iconDna2, iconDollarSign2, iconDonutCoffee2, iconDownload2, iconDrop2, iconEnterpriseBuilding2, iconEnvelope2, iconEnvelopeBug2, iconEnvelopeDoc2, iconEnvelopeShred2, iconExclamationMark2, iconEye2, iconFileApproved2, iconFileBlank2, iconFileBug2, iconFileCheck2, iconFileCloud2, iconFileCopy2, iconFileDocument2, iconFileImage2, iconFileInfographic2, iconFileInsights2, iconFileMove2, iconFileMusic2, iconFilePlus2, iconFilePresentations2, iconFileSpeed2, iconFileSpreadsheet2, iconFileText2, iconFileVideo2, iconFingerPrint2, iconFlight2, iconFolder2, iconFolderUp2, iconFolderUpload2, iconFtpFolder2, iconFunnel2, iconGear2, iconGears2, iconGraduationCap2, iconGraphIncrease2, iconGraphMeasure2, iconGroupCall2, iconHeart2, iconHome2, iconImage2, iconKeySafe2, iconLeavesGrowing2, iconLight2, iconLineGraphV22, iconLineGraph2, iconLink2, iconLock2, iconMagnifyingGlass2, iconMartini2, iconMaze2, iconMedTool2, iconMegaphone2, iconMetadata2, iconMicrophone2, iconMinus2, iconMixedMediaDownload2, iconMusicNote2, iconNotePad2, iconNumber02, iconNumber12, iconNumber22, iconNumber32, iconNumber42, iconNumber52, iconNumber62, iconNumber72, iconNumber82, iconNumber92, iconOMaru2, iconOverlay2, iconPaper2, iconPen2, iconPerson2, iconPhone3, iconPhone1, iconPhoneBrowser2, iconPieChart2, iconPieChart32, iconPin3, iconPin1, iconPlane2, iconPlay2, iconPlus2, iconPodium2, iconPoint2, iconPointCenter2, iconQuestionMark2, iconRaft2, iconRetailTag2, iconRightToForget2, iconRing2, iconRocket2, iconScale3, iconScale1, iconScan2, iconServer2, iconShakeLove2, iconSharedUsers2, iconShield2Tone2, iconShieldCheck2, iconShieldVarified2, iconSlice2, iconSlider2, iconSmbBuilding2, iconSolidArrowDown2, iconSolidArrowRight2, iconSolidCheck2, iconSolidCheckmark2, iconSolidClock12, iconSolidClock22, iconSolidCompass2, iconSolidDollarSign2, iconSolidExclamationMark2, iconSolidMinus2, iconSolidOMaru2, iconSolidPlay2, iconSolidPlus2, iconSolidQuestionMark2, iconSolidXBatsu2, iconSpeachBubble2, iconSpotlight2, iconSprayBottle2, iconSquaresScale2, iconSquaresScaleTop2, iconSquaresTogether2, iconStar2, iconStopHand2, iconStorage2, iconStorageCloud2, iconStorageKey2, iconSun2, iconTarget2, iconTeam2, iconTeamAdd2, iconThumb2, iconToggle2, iconTools2, iconTrophy2, iconTruck2, iconTwoFiles2, iconTyping2, iconTypingNow2, iconUpDown2, iconUpload2, iconUploadCloud2, iconUsb2, iconUserAlert2, iconUserVerifiedUnknown2, iconUserVerified2, iconUserBadge2, iconUserPrimary2, iconUserTimed2, iconVideo2, iconVideoCamera3, iconVideoCamera1, iconWhiteArrowRight, iconWhiteCheck, iconWhitePlus, iconWhiteStop, iconWriting2, iconXBatsu2, iconZones2, } from "../box-iconography.generated.js";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/* auto-generated by tools/iconography/generate-box-iconography.ts */
|
|
2
|
+
export { icon2Chat, icon2ChatQuestion, icon2OverlaySquares, icon3OverlaySquares, icon3SquareCircle, icon3Tier, icon4Squares, icon4Squares2, icon6Dots, iconAddSmall, iconAddSquares, iconAddToCart, iconAid, iconAppCloud, iconArrowDown, iconArrowRight, iconAttachment, iconAudio, iconAward, iconBadge, iconBag, iconBank, iconBattery, iconBell, iconBinders, iconBolt, iconBoltBubble, iconBrain, iconBriefcase, iconBroadcast, iconBrowser, iconBrush, iconCalendar, iconCalendar2, iconCalendarAdded, iconCart, iconCart2, iconCash, iconCautionFile, iconCautionPhone, iconCautionTriangle, iconCenter, iconChatBubble, iconChatQuestion, iconCheck, iconCheckmark, iconClipboard, iconClock1, iconClock2, iconClock3, iconCloud, iconCloudServer, iconCode, iconCodeBrowser, iconCompass, iconComputer, iconComputerBadge, iconComputerDownload, iconComputerUpoad, iconConnectedDots, iconConnectedTogether, iconContainerLines, iconContainerLines2, iconCubeDotLine, iconCubeLine, iconCycle, iconDesktopLaptop, iconDevices, iconDistribute, iconDistribute2, iconDna, iconDollarSign, iconDonutCoffee, iconDownload, iconDrop, iconEnterpriseBuilding, iconEnvelope, iconEnvelopeBug, iconEnvelopeDoc, iconEnvelopeShred, iconExclamationMark, iconEye, iconFileApproved, iconFileBlank, iconFileBug, iconFileCheck, iconFileCloud, iconFileCopy, iconFileDocument, iconFileImage, iconFileInfographic, iconFileInsights, iconFileMove, iconFileMusic, iconFilePlus, iconFilePresentations, iconFileSpeed, iconFileSpreadsheet, iconFileText, iconFileVideo, iconFingerPrint, iconFlight, iconFolder, iconFolderUp, iconFolderUpload, iconFtpFolder, iconFunnel, iconGear, iconGears, iconGraduationCap, iconGraphIncrease, iconGraphMeasure, iconGroupCall, iconHeart, iconHome, iconImage, iconKeySafe, iconLeavesGrowing, iconLight, iconLineGraphV2, iconLineGraph, iconLink, iconLock, iconMagnifyingGlass, iconMartini, iconMaze, iconMedTool, iconMegaphone, iconMetadata, iconMicrophone, iconMinus, iconMixedMediaDownload, iconMusicNote, iconNotePad, iconNumber0, iconNumber1, iconNumber2, iconNumber3, iconNumber4, iconNumber5, iconNumber6, iconNumber7, iconNumber8, iconNumber9, iconOMaru, iconOverlay, iconPaper, iconPen, iconPerson, iconPhone, iconPhone2, iconPhoneBrowser, iconPieChart, iconPieChart3, iconPin, iconPin2, iconPlane, iconPlay, iconPlus, iconPodium, iconPoint, iconPointCenter, iconQuestionMark, iconRaft, iconRetailTag, iconRightToForget, iconRing, iconRocket, iconScale, iconScale2, iconScan, iconServer, iconShakeLove, iconSharedUsers, iconShield2Tone, iconShieldCheck, iconShieldVarified, iconSlice, iconSlider, iconSmbBuilding, iconSolidArrowDown, iconSolidArrowRight, iconSolidCheck, iconSolidCheckmark, iconSolidClock1, iconSolidClock2, iconSolidCompass, iconSolidDollarSign, iconSolidExclamationMark, iconSolidMinus, iconSolidOMaru, iconSolidPlay, iconSolidPlus, iconSolidQuestionMark, iconSolidXBatsu, iconSpeachBubble, iconSpotlight, iconSprayBottle, iconSquaresScale, iconSquaresScaleTop, iconSquaresTogether, iconStar, iconStopHand, iconStorage, iconStorageCloud, iconStorageKey, iconSun, iconTarget, iconTeam, iconTeamAdd, iconThumb, iconToggle, iconTools, iconTrophy, iconTruck, iconTwoFiles, iconTyping, iconTypingNow, iconUpDown, iconUpload, iconUploadCloud, iconUsb, iconUserAlert, iconUserVerified, iconUserVerifiedUnknown, iconUserBadge, iconUserPrimary, iconUserTimed, iconVideo, iconVideoCamera, iconVideoCamera2, iconWriting, iconXBatsu, iconZones, icon2Chat2, icon2ChatQuestion2, icon2OverlaySquares2, icon3OverlaySquares2, icon3SquareCircle2, icon3Tier2, icon4Squares3, icon4Squares1, icon6Dots2, iconAddSmall2, iconAddSquares2, iconAddToCart2, iconAid2, iconAppCloud2, iconArrowDown2, iconArrowRight2, iconAttachment2, iconAudio2, iconAward2, iconBadge2, iconBag2, iconBank2, iconBattery2, iconBell2, iconBinders2, iconBolt2, iconBoltBubble2, iconBrain2, iconBriefcase2, iconBroadcast2, iconBrowser2, iconBrush2, iconCalendar3, iconCalendar1, iconCalendarAdded2, iconCart3, iconCart1, iconCash2, iconCautionFile2, iconCautionPhone2, iconCautionTriangle2, iconCenter2, iconChatBubble2, iconChatQuestion2, iconCheck2, iconCheckmark2, iconClipboard2, iconClock12, iconClock22, iconClock32, iconCloud2, iconCloudServer2, iconCode2, iconCodeBrowser2, iconCompass2, iconComputer2, iconComputerBadge2, iconComputerDownload2, iconComputerUpoad2, iconConnectedDots2, iconConnectedTogether2, iconContainerLines3, iconContainerLines22, iconCubeDotLine2, iconCubeLine2, iconCycle2, iconDesktopLaptop2, iconDevices2, iconDistribute3, iconDistribute1, iconDna2, iconDollarSign2, iconDonutCoffee2, iconDownload2, iconDrop2, iconEnterpriseBuilding2, iconEnvelope2, iconEnvelopeBug2, iconEnvelopeDoc2, iconEnvelopeShred2, iconExclamationMark2, iconEye2, iconFileApproved2, iconFileBlank2, iconFileBug2, iconFileCheck2, iconFileCloud2, iconFileCopy2, iconFileDocument2, iconFileImage2, iconFileInfographic2, iconFileInsights2, iconFileMove2, iconFileMusic2, iconFilePlus2, iconFilePresentations2, iconFileSpeed2, iconFileSpreadsheet2, iconFileText2, iconFileVideo2, iconFingerPrint2, iconFlight2, iconFolder2, iconFolderUp2, iconFolderUpload2, iconFtpFolder2, iconFunnel2, iconGear2, iconGears2, iconGraduationCap2, iconGraphIncrease2, iconGraphMeasure2, iconGroupCall2, iconHeart2, iconHome2, iconImage2, iconKeySafe2, iconLeavesGrowing2, iconLight2, iconLineGraphV22, iconLineGraph2, iconLink2, iconLock2, iconMagnifyingGlass2, iconMartini2, iconMaze2, iconMedTool2, iconMegaphone2, iconMetadata2, iconMicrophone2, iconMinus2, iconMixedMediaDownload2, iconMusicNote2, iconNotePad2, iconNumber02, iconNumber12, iconNumber22, iconNumber32, iconNumber42, iconNumber52, iconNumber62, iconNumber72, iconNumber82, iconNumber92, iconOMaru2, iconOverlay2, iconPaper2, iconPen2, iconPerson2, iconPhone3, iconPhone1, iconPhoneBrowser2, iconPieChart2, iconPieChart32, iconPin3, iconPin1, iconPlane2, iconPlay2, iconPlus2, iconPodium2, iconPoint2, iconPointCenter2, iconQuestionMark2, iconRaft2, iconRetailTag2, iconRightToForget2, iconRing2, iconRocket2, iconScale3, iconScale1, iconScan2, iconServer2, iconShakeLove2, iconSharedUsers2, iconShield2Tone2, iconShieldCheck2, iconShieldVarified2, iconSlice2, iconSlider2, iconSmbBuilding2, iconSolidArrowDown2, iconSolidArrowRight2, iconSolidCheck2, iconSolidCheckmark2, iconSolidClock12, iconSolidClock22, iconSolidCompass2, iconSolidDollarSign2, iconSolidExclamationMark2, iconSolidMinus2, iconSolidOMaru2, iconSolidPlay2, iconSolidPlus2, iconSolidQuestionMark2, iconSolidXBatsu2, iconSpeachBubble2, iconSpotlight2, iconSprayBottle2, iconSquaresScale2, iconSquaresScaleTop2, iconSquaresTogether2, iconStar2, iconStopHand2, iconStorage2, iconStorageCloud2, iconStorageKey2, iconSun2, iconTarget2, iconTeam2, iconTeamAdd2, iconThumb2, iconToggle2, iconTools2, iconTrophy2, iconTruck2, iconTwoFiles2, iconTyping2, iconTypingNow2, iconUpDown2, iconUpload2, iconUploadCloud2, iconUsb2, iconUserAlert2, iconUserVerifiedUnknown2, iconUserVerified2, iconUserBadge2, iconUserPrimary2, iconUserTimed2, iconVideo2, iconVideoCamera3, iconVideoCamera1, iconWhiteArrowRight, iconWhiteCheck, iconWhitePlus, iconWhiteStop, iconWriting2, iconXBatsu2, iconZones2, } from "../box-iconography.generated.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module","sideEffects":false}
|
|
@@ -91,6 +91,13 @@ export const resolvePosition = (anchor, floating, viewport, options = {}) => {
|
|
|
91
91
|
if (shift)
|
|
92
92
|
y = clamp(y, padding, viewport.height - floating.height - padding);
|
|
93
93
|
}
|
|
94
|
+
// On a narrow viewport neither side may fit (a right popover can flip to a
|
|
95
|
+
// still-offscreen left position). Keep the surface reachable after flipping.
|
|
96
|
+
// Explicit flip/shift opt-outs retain the requested overflow behavior.
|
|
97
|
+
if (flip && shift) {
|
|
98
|
+
x = clamp(x, padding, viewport.width - floating.width - padding);
|
|
99
|
+
y = clamp(y, padding, viewport.height - floating.height - padding);
|
|
100
|
+
}
|
|
94
101
|
return { x, y, side, align };
|
|
95
102
|
};
|
|
96
103
|
/** Parse a placement string like `"bottom-start"` / `"top"` / `"right-center"`. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type StatusKind = "pending" | "active" | "done" | "warning" | "failed" | "skipped";
|
|
1
|
+
export type StatusKind = "pending" | "active" | "done" | "warning" | "failed" | "skipped" | "approved" | "rejected";
|
|
2
2
|
export declare const toStatusKind: (status: string) => StatusKind;
|
|
3
3
|
export declare const statusLabel: (kind: StatusKind) => string;
|
|
4
4
|
/** Decorative markup. Pair with visible words or the StatusIcon component. */
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
const mappings = {
|
|
2
2
|
pending: "pending", info: "pending", active: "active", running: "active", in_progress: "active",
|
|
3
|
-
done: "done", succeeded: "done", completed: "done", pass: "done", approved: "
|
|
3
|
+
done: "done", succeeded: "done", completed: "done", pass: "done", approved: "approved",
|
|
4
4
|
warning: "warning", warn: "warning", failed: "failed", fail: "failed", error: "failed",
|
|
5
|
-
skipped: "skipped", rejected: "
|
|
5
|
+
skipped: "skipped", rejected: "rejected",
|
|
6
6
|
};
|
|
7
7
|
export const toStatusKind = (status) => mappings[status] ?? "pending";
|
|
8
8
|
export const statusLabel = (kind) => ({
|
|
9
9
|
pending: "Pending", active: "In progress", done: "Done", warning: "Done with a warning",
|
|
10
10
|
failed: "Failed", skipped: "Skipped",
|
|
11
|
+
approved: "Approved", rejected: "Rejected",
|
|
11
12
|
})[kind];
|
|
12
13
|
/** Decorative markup. Pair with visible words or the StatusIcon component. */
|
|
13
14
|
export const boeStatusGlyph = (kind) => {
|
|
14
15
|
const state = toStatusKind(kind);
|
|
15
|
-
const path = state === "done" ? '<path d="m4 8 3 3 5-6"/>'
|
|
16
|
-
: state === "
|
|
17
|
-
: state === "
|
|
18
|
-
: state === "
|
|
16
|
+
const path = state === "done" || state === "approved" ? '<path d="m4 8 3 3 5-6"/>'
|
|
17
|
+
: state === "rejected" ? '<path d="M4 12 12 4"/>'
|
|
18
|
+
: state === "failed" ? '<path d="m5 5 6 6m0-6-6 6"/>'
|
|
19
|
+
: state === "warning" ? '<path d="M5 8h6"/>'
|
|
20
|
+
: state === "active" ? '<path d="M8 1a7 7 0 0 1 7 7"/>' : "";
|
|
19
21
|
return `<svg class="boe-status" data-kind="${state}" aria-hidden="true" viewBox="0 0 16 16" width="16" height="16"><circle cx="8" cy="8" r="7"/>${path}</svg>`;
|
|
20
22
|
};
|
|
21
23
|
export const boeStatusStyles = `
|
|
@@ -36,7 +36,10 @@ export const boxDarkDesignSystem = {
|
|
|
36
36
|
TextTextDanger: "#ff8a9b",
|
|
37
37
|
TextTextSecondary: "#bcbcbc",
|
|
38
38
|
TextTextPlaceholder: "#909090",
|
|
39
|
-
TextTextOnBrand: "#
|
|
39
|
+
TextTextOnBrand: "#101010",
|
|
40
|
+
TextStatusTextSuccess: "#2ed58f",
|
|
41
|
+
TextStatusTextWarning: "#ffc447",
|
|
42
|
+
TextStatusTextError: "#ff8a9b",
|
|
40
43
|
StrokeStroke: "#3a3a3a",
|
|
41
44
|
StrokeStrokeHover: "#4e4e4e",
|
|
42
45
|
},
|
|
@@ -34,6 +34,9 @@ export const boxDefaultDesignSystem = {
|
|
|
34
34
|
TextTextPlaceholder: "#909090",
|
|
35
35
|
TextTextOnBrand: "#ffffff",
|
|
36
36
|
TextTextDanger: "#d5324e",
|
|
37
|
+
TextStatusTextSuccess: "#187657",
|
|
38
|
+
TextStatusTextWarning: "#805600",
|
|
39
|
+
TextStatusTextError: "#b92340",
|
|
37
40
|
StrokeStroke: "#e8e8e8",
|
|
38
41
|
StrokeStrokeHover: "#bcbcbc",
|
|
39
42
|
},
|
|
@@ -26,6 +26,9 @@ export declare const SEMANTIC_TOKEN_ALIASES: {
|
|
|
26
26
|
readonly textPlaceholder: "TextTextPlaceholder";
|
|
27
27
|
readonly textOnBrand: "TextTextOnBrand";
|
|
28
28
|
readonly textDanger: "TextTextDanger";
|
|
29
|
+
readonly textStatusSuccess: "TextStatusTextSuccess";
|
|
30
|
+
readonly textStatusWarning: "TextStatusTextWarning";
|
|
31
|
+
readonly textStatusError: "TextStatusTextError";
|
|
29
32
|
readonly borderDefault: "StrokeStroke";
|
|
30
33
|
readonly borderHover: "StrokeStrokeHover";
|
|
31
34
|
};
|
|
@@ -28,6 +28,9 @@ export const SEMANTIC_TOKEN_ALIASES = {
|
|
|
28
28
|
textPlaceholder: "TextTextPlaceholder",
|
|
29
29
|
textOnBrand: "TextTextOnBrand",
|
|
30
30
|
textDanger: "TextTextDanger",
|
|
31
|
+
textStatusSuccess: "TextStatusTextSuccess",
|
|
32
|
+
textStatusWarning: "TextStatusTextWarning",
|
|
33
|
+
textStatusError: "TextStatusTextError",
|
|
31
34
|
borderDefault: "StrokeStroke",
|
|
32
35
|
borderHover: "StrokeStrokeHover",
|
|
33
36
|
};
|
|
@@ -29,6 +29,9 @@ export interface SemanticDesignTokenMap {
|
|
|
29
29
|
textPlaceholder?: string;
|
|
30
30
|
textOnBrand?: string;
|
|
31
31
|
textDanger?: string;
|
|
32
|
+
textStatusSuccess?: string;
|
|
33
|
+
textStatusWarning?: string;
|
|
34
|
+
textStatusError?: string;
|
|
32
35
|
borderDefault?: string;
|
|
33
36
|
borderHover?: string;
|
|
34
37
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -144,3 +144,5 @@ export * from "./patterns/agent-workspace/index.js";
|
|
|
144
144
|
export * from "./patterns/call-console/index.js";
|
|
145
145
|
export * from "./foundations/status/index.js";
|
|
146
146
|
export * from "./patterns/run/progress.js";
|
|
147
|
+
export * from "./patterns/undo/index.js";
|
|
148
|
+
export * from "./patterns/flow-builder/index.js";
|
package/dist/index.js
CHANGED
|
@@ -158,3 +158,5 @@ export * from "./patterns/agent-workspace/index.js";
|
|
|
158
158
|
export * from "./patterns/call-console/index.js";
|
|
159
159
|
export * from "./foundations/status/index.js";
|
|
160
160
|
export * from "./patterns/run/progress.js";
|
|
161
|
+
export * from "./patterns/undo/index.js";
|
|
162
|
+
export * from "./patterns/flow-builder/index.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AgentChatController } from "./controller.js";
|
|
2
2
|
import { isSafeHref } from "../internal/safe-href.js";
|
|
3
3
|
import { BaseElement } from "../../core/index.js";
|
|
4
|
+
import { announce } from "../../foundations/a11y/index.js";
|
|
4
5
|
import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
|
|
5
6
|
import { boePanel, boeRadius } from "../../foundations/geometry/index.js";
|
|
6
7
|
import { ScrollPinController, boeEntranceKeyframes, boeReducedMotionPolicy } from "../../foundations/motion/index.js";
|
|
@@ -242,7 +243,7 @@ const elementStyles = `
|
|
|
242
243
|
gap: 0.4rem;
|
|
243
244
|
}
|
|
244
245
|
|
|
245
|
-
[part="proposal-action"] {
|
|
246
|
+
[part="proposal-action"], [part="option"], [part="retry"] {
|
|
246
247
|
appearance: none;
|
|
247
248
|
font: inherit;
|
|
248
249
|
font-size: 0.78rem;
|
|
@@ -256,7 +257,9 @@ const elementStyles = `
|
|
|
256
257
|
transition: background ${boeMotionDuration.interactive} ${boeMotionEasing.standard};
|
|
257
258
|
}
|
|
258
259
|
|
|
259
|
-
[part="
|
|
260
|
+
[part="option"], [part="retry"] { justify-self: start; min-height: 32px; text-align: left; }
|
|
261
|
+
|
|
262
|
+
[part="proposal-action"]:hover, [part="option"]:hover, [part="retry"]:hover {
|
|
260
263
|
background: var(--boe-token-surface-surface-hover, #f4f4f4);
|
|
261
264
|
}
|
|
262
265
|
|
|
@@ -270,7 +273,7 @@ const elementStyles = `
|
|
|
270
273
|
color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 74%, black 26%);
|
|
271
274
|
}
|
|
272
275
|
|
|
273
|
-
[part="proposal-action"]:focus-visible {
|
|
276
|
+
[part="proposal-action"]:focus-visible, [part="option"]:focus-visible, [part="retry"]:focus-visible {
|
|
274
277
|
outline: none;
|
|
275
278
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 18%, transparent);
|
|
276
279
|
}
|
|
@@ -563,6 +566,11 @@ export class AgentChat extends BaseElement {
|
|
|
563
566
|
["actionResolved", "action-resolved"],
|
|
564
567
|
];
|
|
565
568
|
this.unsubscribeFns = events.map(([eventName, domEventName]) => controller.subscribe(eventName, payload => {
|
|
569
|
+
if (eventName === "actionResolved") {
|
|
570
|
+
const { proposal, decision } = payload;
|
|
571
|
+
const failed = proposal.outcome === "failed";
|
|
572
|
+
announce(`${proposal.title}: ${failed ? "Approved, but did not complete" : decision === "approved" ? "Approved" : "Rejected"}${proposal.note ? `. ${proposal.note}` : ""}`, failed ? "assertive" : "polite", this.ownerDocument);
|
|
573
|
+
}
|
|
566
574
|
this.dispatchEvent(new CustomEvent(domEventName, {
|
|
567
575
|
bubbles: true,
|
|
568
576
|
composed: true,
|
|
@@ -598,7 +606,7 @@ export class AgentChat extends BaseElement {
|
|
|
598
606
|
.map(proposal => {
|
|
599
607
|
if (proposal.decision) {
|
|
600
608
|
const failed = proposal.outcome === "failed";
|
|
601
|
-
return `<div part="proposal" tabindex="-1" id="${this.proposalAnchor(message.id, proposal.id)}" data-proposal-id="${escapeHtml(proposal.id)}" data-decision="${escapeHtml(proposal.decision)}" ${failed ? 'role="alert"' : ""}>
|
|
609
|
+
return `<div part="proposal" aria-live="off" tabindex="-1" id="${this.proposalAnchor(message.id, proposal.id)}" data-proposal-id="${escapeHtml(proposal.id)}" data-decision="${escapeHtml(proposal.decision)}" ${failed ? 'role="alert"' : ""}>
|
|
602
610
|
<span part="decision">${boeStatusGlyph(failed ? "failed" : proposal.decision === "approved" ? "done" : "skipped")}${proposal.decision === "approved" ? failed ? "Approved · didn't complete" : "Approved" : "Rejected"} · <span part="proposal-title">${escapeHtml(proposal.title)}</span></span>
|
|
603
611
|
${proposal.note ? `<p part="proposal-note">${escapeHtml(proposal.note)}</p>` : ""}
|
|
604
612
|
${failed ? `<button part="retry" data-message-id="${escapeHtml(message.id)}">Try again</button>` : ""}</div>`;
|
|
@@ -6,6 +6,8 @@ export declare class CallConsole extends BaseElement {
|
|
|
6
6
|
private model;
|
|
7
7
|
private unsubscribe?;
|
|
8
8
|
private selected;
|
|
9
|
+
private clearing;
|
|
10
|
+
private rowSignatures;
|
|
9
11
|
get callController(): CallConsoleController | null;
|
|
10
12
|
set callController(value: CallConsoleController | null);
|
|
11
13
|
private listen;
|
|
@@ -13,5 +15,6 @@ export declare class CallConsole extends BaseElement {
|
|
|
13
15
|
disconnectedCallback(): void;
|
|
14
16
|
protected renderTemplate(): void;
|
|
15
17
|
protected setupListeners(): void;
|
|
18
|
+
private get filters();
|
|
16
19
|
protected update(): void;
|
|
17
20
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { BaseElement } from "../../core/element.js";
|
|
2
2
|
import { SplitView } from "../../components/layout/split-view.js";
|
|
3
|
+
import { Button } from "../../components/actions/button.js";
|
|
4
|
+
import { CodeBlock } from "../../components/output/code-block.js";
|
|
5
|
+
import { boeControl, boeRadius } from "../../foundations/geometry/index.js";
|
|
6
|
+
import { boeStatusGlyph, boeStatusStyles } from "../../foundations/status/index.js";
|
|
3
7
|
import { boeEntrance, boeEntranceKeyframes, boeReducedMotionPolicy } from "../../foundations/motion/index.js";
|
|
4
8
|
import { callFailed, callStatus, formatCallHttp } from "./types.js";
|
|
5
9
|
const DEFAULT_TAG_NAME = "box-call-console";
|
|
@@ -29,6 +33,8 @@ export class CallConsole extends BaseElement {
|
|
|
29
33
|
model = null;
|
|
30
34
|
unsubscribe;
|
|
31
35
|
selected = "";
|
|
36
|
+
clearing = false;
|
|
37
|
+
rowSignatures = new WeakMap();
|
|
32
38
|
get callController() { return this.model; }
|
|
33
39
|
set callController(value) { this.unsubscribe?.(); this.model = value; if (this.isConnected)
|
|
34
40
|
this.listen(); if (this.isRendered)
|
|
@@ -38,21 +44,73 @@ export class CallConsole extends BaseElement {
|
|
|
38
44
|
disconnectedCallback() { this.unsubscribe?.(); }
|
|
39
45
|
renderTemplate() {
|
|
40
46
|
SplitView.register();
|
|
47
|
+
Button.register();
|
|
48
|
+
CodeBlock.register();
|
|
41
49
|
this.shadowRoot.innerHTML = `<style>:host{display:block;min-width:0;color:var(--boe-token-text-text,#222);font:inherit}:host([hidden]){display:none !important}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
[part="
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
:host{container-type:inline-size;font-size:14px;line-height:1.5}
|
|
51
|
+
*{box-sizing:border-box} [hidden]{display:none!important}
|
|
52
|
+
[part="console"]{border:1px solid var(--boe-token-stroke-stroke,#ddd);border-radius:${boeRadius.large};background:var(--boe-token-surface-surface,#fff);overflow:hidden}
|
|
53
|
+
header,.filters,.pane-heading{display:flex;gap:.75rem;flex-wrap:wrap;align-items:center;padding:1rem}
|
|
54
|
+
header{justify-content:space-between} h2,h3,p{margin:0} h2{font-size:16px} h3{font-size:14px} small,.muted{color:var(--boe-token-text-text-secondary,#666);font-size:12px}
|
|
55
|
+
#connection{display:inline-flex;align-items:center;gap:.4rem;font-size:12px}
|
|
56
|
+
.filters{border-block:1px solid var(--boe-token-stroke-stroke,#ddd);background:var(--boe-token-surface-surface-secondary,#f7f7f7);padding:.75rem 1rem}
|
|
57
|
+
label{display:flex;align-items:center;gap:.5rem;font-size:13px} .search{flex:1;min-width:10rem} .search input{width:100%}
|
|
58
|
+
input[type="search"],select{min-height:${boeControl.height};border:1px solid var(--boe-token-stroke-stroke,#ccc);border-radius:${boeRadius.control};background:var(--boe-token-surface-surface,#fff);color:inherit;font:inherit;padding:.35rem .65rem;min-width:0}
|
|
59
|
+
input[type="checkbox"]{accent-color:var(--boe-token-surface-surface-brand,#0061d5)}
|
|
60
|
+
button:focus-visible,input:focus-visible,select:focus-visible{outline:2px solid var(--boe-token-surface-surface-brand,#0061d5);outline-offset:-2px}
|
|
61
|
+
.pane-heading{justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--boe-token-stroke-stroke,#ddd)}
|
|
62
|
+
#list{overflow:auto;max-height:34rem;min-height:20rem;padding:.35rem}
|
|
63
|
+
[part="call"]{font:inherit;color:inherit;border:1px solid transparent;background:transparent;border-radius:${boeRadius.med};width:100%;display:grid;grid-template-columns:minmax(0,1fr) auto;text-align:left;gap:.3rem .75rem;padding:.75rem;cursor:pointer;${boeEntrance()}}
|
|
64
|
+
[part="call"]:hover{background:var(--boe-token-surface-surface-secondary,#f5f5f5)}
|
|
65
|
+
[part="call"][aria-current="true"]{background:var(--boe-token-surface-item-surface-selected,#eaf3ff);border-color:var(--boe-token-surface-surface-brand,#0061d5)}
|
|
66
|
+
[part="call"] span{min-width:0;overflow-wrap:anywhere} [part="call"] .state{display:flex;gap:.4rem;align-items:center;font-size:12px} [part="call"] .summary{font-weight:600} [part="call"] .duration{text-align:right;font-variant-numeric:tabular-nums;font-size:12px}
|
|
67
|
+
#inspector{padding:1rem;min-width:0;max-height:38rem;overflow:auto} #summary{font-size:15px;overflow-wrap:anywhere} #metadata{margin:.25rem 0 1rem;overflow-wrap:anywhere} .code-heading{margin:1rem 0 .5rem}
|
|
68
|
+
#outcome{padding:.6rem .75rem;margin:.75rem 0;border-radius:${boeRadius.med};background:var(--boe-token-surface-surface-secondary,#f5f5f5);overflow-wrap:anywhere}
|
|
69
|
+
#copy-status{font-size:12px;color:var(--boe-token-text-text-secondary,#666)}
|
|
70
|
+
#list-empty,#detail-empty{padding:2.5rem 1rem;text-align:center;color:var(--boe-token-text-text-secondary,#666)}
|
|
71
|
+
[part="skeleton"]{height:3rem;margin:.5rem;background:var(--boe-token-surface-surface-secondary,#eee);border-radius:${boeRadius.med}}
|
|
72
|
+
box-code-block::part(pre){max-height:18rem;overflow:auto}
|
|
73
|
+
@container(max-width:640px){box-split-view::part(split-view){grid-template-columns:minmax(0,1fr)!important}box-split-view::part(separator){display:none}#list{min-height:0;max-height:17rem}#inspector{border-top:1px solid var(--boe-token-stroke-stroke,#ddd)}.search{flex-basis:100%}}
|
|
74
|
+
${boeEntranceKeyframes}${boeStatusStyles}${boeReducedMotionPolicy}</style>
|
|
75
|
+
<section part="console" aria-label="API call console">
|
|
76
|
+
<header><div><h2>API calls</h2><small>Inspect requests, responses, and tool outcomes</small></div><span id="connection" role="status"></span><box-button id="retry" label="Reconnect" tone="neutral" hidden></box-button></header>
|
|
77
|
+
<div class="filters"><label class="search">Search <input id="search" type="search" placeholder="Method, URL, or summary"></label><label>Service <select id="service" aria-label="Service"><option value="">All services</option></select></label><label><input type="checkbox" id="errors"> Errors only</label><box-button id="clear" label="Clear calls" tone="neutral"></box-button></div>
|
|
78
|
+
<box-split-view resizable ratio="0.42" label="Calls and request inspector"><section slot="primary" aria-label="Calls"><div class="pane-heading"><h3>Requests</h3><span id="count" class="muted" role="status"></span></div><div id="list"></div><p id="list-empty" role="status" hidden></p></section><section aria-label="Request inspector"><div class="pane-heading"><h3>Inspector</h3><box-button data-copy="both" label="Copy both" tone="neutral"></box-button><span id="copy-status" role="status"></span></div><p id="detail-empty">Select a request to inspect its details.</p><div id="inspector" hidden><h3 id="summary"></h3><p id="metadata" class="muted"></p><p id="outcome" role="status" hidden></p><h3 class="code-heading">Request</h3><box-code-block id="request" copy-label="Copy request" wrap></box-code-block><h3 class="code-heading">Response</h3><box-code-block id="response" copy-label="Copy response" wrap></box-code-block></div></section></box-split-view></section>`;
|
|
51
79
|
}
|
|
52
80
|
setupListeners() {
|
|
53
|
-
this.shadowRoot.querySelector("#
|
|
54
|
-
|
|
55
|
-
|
|
81
|
+
this.shadowRoot.querySelector("#list").addEventListener("keydown", event => {
|
|
82
|
+
const e = event;
|
|
83
|
+
const rows = Array.from(this.shadowRoot.querySelectorAll('[part="call"]'));
|
|
84
|
+
const current = rows.indexOf(e.target);
|
|
85
|
+
if (current < 0 || !["ArrowDown", "ArrowUp", "Home", "End"].includes(e.key))
|
|
86
|
+
return;
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
const next = e.key === "Home" ? 0 : e.key === "End" ? rows.length - 1 : (current + (e.key === "ArrowDown" ? 1 : -1) + rows.length) % rows.length;
|
|
89
|
+
rows[next].focus();
|
|
90
|
+
rows[next].click();
|
|
91
|
+
});
|
|
92
|
+
const filter = () => { this.update(); this.dispatchEvent(new CustomEvent("filters-changed", { bubbles: true, composed: true, detail: this.filters })); };
|
|
93
|
+
this.shadowRoot.querySelector("#service").addEventListener("change", filter);
|
|
94
|
+
this.shadowRoot.querySelector("#errors").addEventListener("change", filter);
|
|
95
|
+
this.shadowRoot.querySelector("#search").addEventListener("input", filter);
|
|
96
|
+
this.shadowRoot.querySelector("#retry").addEventListener("click", () => { void this.model?.connect(); });
|
|
97
|
+
this.shadowRoot.querySelector("#clear").addEventListener("click", async () => {
|
|
98
|
+
if (!this.model || this.clearing)
|
|
99
|
+
return;
|
|
100
|
+
this.clearing = true;
|
|
101
|
+
this.update();
|
|
102
|
+
try {
|
|
103
|
+
await this.model.clear();
|
|
104
|
+
this.dispatchEvent(new CustomEvent("calls-cleared", { bubbles: true, composed: true }));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
this.shadowRoot.querySelector("#copy-status").textContent = "Unable to clear calls. Try again.";
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
this.clearing = false;
|
|
111
|
+
this.update();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
56
114
|
this.shadowRoot.querySelectorAll("[data-copy]").forEach(b => b.addEventListener("click", async () => {
|
|
57
115
|
const entry = this.model?.entries.find(e => e.id === this.selected);
|
|
58
116
|
if (!entry)
|
|
@@ -61,9 +119,19 @@ export class CallConsole extends BaseElement {
|
|
|
61
119
|
this.shadowRoot.querySelector("#copy-status").textContent = ok ? "Copied" : "Copy unavailable; select the text to copy";
|
|
62
120
|
}));
|
|
63
121
|
}
|
|
122
|
+
get filters() {
|
|
123
|
+
return { service: this.shadowRoot.querySelector("#service").value, errorsOnly: this.shadowRoot.querySelector("#errors").checked, query: this.shadowRoot.querySelector("#search").value };
|
|
124
|
+
}
|
|
64
125
|
update() {
|
|
126
|
+
if (!this.isRendered)
|
|
127
|
+
return;
|
|
65
128
|
const state = this.model?.connection ?? "connecting";
|
|
66
|
-
this.shadowRoot.querySelector("#connection")
|
|
129
|
+
const connection = this.shadowRoot.querySelector("#connection");
|
|
130
|
+
connection.textContent = this.model ? ({ live: "Live", connecting: "Connecting…", reconnecting: "Reconnecting…", unavailable: "Endpoint unavailable" }[state]) : "Not connected";
|
|
131
|
+
this.shadowRoot.querySelector("#retry").hidden = !this.model || state === "live" || state === "connecting";
|
|
132
|
+
const clear = this.shadowRoot.querySelector("#clear");
|
|
133
|
+
clear.disabled = this.clearing || !this.model?.entries.length;
|
|
134
|
+
clear.label = this.clearing ? "Clearing…" : "Clear calls";
|
|
67
135
|
const service = this.shadowRoot.querySelector("#service");
|
|
68
136
|
const services = [...new Set(this.model?.entries.map(e => e.service) ?? [])];
|
|
69
137
|
for (const name of services)
|
|
@@ -75,33 +143,59 @@ export class CallConsole extends BaseElement {
|
|
|
75
143
|
}
|
|
76
144
|
const errors = this.shadowRoot.querySelector("#errors").checked;
|
|
77
145
|
const entries = this.model?.entries.filter(e => (!service.value || e.service === service.value) && (!errors || callFailed(e))) ?? [];
|
|
146
|
+
const query = this.filters.query.trim().toLowerCase();
|
|
147
|
+
const filtered = entries.filter(e => `${e.method} ${e.url} ${e.summary} ${e.service}`.toLowerCase().includes(query));
|
|
148
|
+
entries.splice(0, entries.length, ...filtered);
|
|
78
149
|
if (!entries.some(e => e.id === this.selected))
|
|
79
150
|
this.selected = entries[0]?.id ?? "";
|
|
80
151
|
const list = this.shadowRoot.querySelector("#list");
|
|
81
152
|
const focused = this.shadowRoot.activeElement?.getAttribute("data-call-id");
|
|
82
153
|
list.querySelectorAll('[part="skeleton"]').forEach(el => el.remove());
|
|
83
154
|
const existing = new Map(Array.from(list.children).map(el => [el.getAttribute("data-call-id"), el]));
|
|
84
|
-
for (const entry of entries) {
|
|
155
|
+
for (const [index, entry] of entries.entries()) {
|
|
85
156
|
let button = existing.get(entry.id);
|
|
86
157
|
existing.delete(entry.id);
|
|
87
158
|
if (!button) {
|
|
88
159
|
button = document.createElement("button");
|
|
160
|
+
button.type = "button";
|
|
89
161
|
button.setAttribute("part", "call");
|
|
90
162
|
button.dataset.callId = entry.id;
|
|
91
|
-
button.addEventListener("click", () => { this.selected = entry.id; this.update(); });
|
|
163
|
+
button.addEventListener("click", () => { this.selected = entry.id; this.update(); this.dispatchEvent(new CustomEvent("call-selected", { bubbles: true, composed: true, detail: { id: entry.id } })); });
|
|
92
164
|
}
|
|
93
165
|
button.setAttribute("aria-current", String(entry.id === this.selected));
|
|
94
|
-
|
|
95
|
-
|
|
166
|
+
const labels = [callStatus(entry), entry.service, entry.summary, entry.pending ? "In progress" : `${Math.round(entry.durationMs)} ms`];
|
|
167
|
+
const signature = JSON.stringify(labels);
|
|
168
|
+
if (this.rowSignatures.get(button) !== signature) {
|
|
169
|
+
button.replaceChildren(...labels.map((text, index) => { const span = document.createElement("span"); span.textContent = text; span.className = ["state", "muted", "summary", "duration"][index]; if (index === 0) {
|
|
170
|
+
const icon = document.createElement("span");
|
|
171
|
+
icon.innerHTML = boeStatusGlyph(entry.pending ? "active" : callFailed(entry) ? "failed" : entry.expected ? "skipped" : "done");
|
|
172
|
+
span.prepend(icon);
|
|
173
|
+
} return span; }));
|
|
174
|
+
this.rowSignatures.set(button, signature);
|
|
175
|
+
}
|
|
176
|
+
if (list.children[index] !== button)
|
|
177
|
+
list.insertBefore(button, list.children[index] ?? null);
|
|
96
178
|
if (entry.id === focused)
|
|
97
179
|
button.focus({ preventScroll: true });
|
|
98
180
|
}
|
|
99
181
|
existing.forEach(el => el.remove());
|
|
100
|
-
if (!entries.length && state === "connecting")
|
|
182
|
+
if (!entries.length && state === "connecting" && this.model)
|
|
101
183
|
list.innerHTML = '<div part="skeleton"></div><div part="skeleton"></div><div part="skeleton"></div>';
|
|
184
|
+
this.shadowRoot.querySelector("#count").textContent = `${entries.length} of ${this.model?.entries.length ?? 0}`;
|
|
185
|
+
const empty = this.shadowRoot.querySelector("#list-empty");
|
|
186
|
+
empty.hidden = entries.length > 0 || !!this.model && state === "connecting";
|
|
187
|
+
empty.textContent = !this.model ? "Connect a call controller to inspect requests." : state === "unavailable" ? "The /calls endpoint is unavailable. Start the agent, then reconnect." : state === "reconnecting" ? "Connection interrupted. Reconnect to load calls." : this.model.entries.length ? "No requests match these filters." : "No calls yet. New requests will appear here.";
|
|
102
188
|
const entry = entries.find(e => e.id === this.selected);
|
|
103
|
-
this.shadowRoot.querySelector("
|
|
104
|
-
this.shadowRoot.querySelector("#
|
|
189
|
+
this.shadowRoot.querySelector('[data-copy="both"]').disabled = !entry;
|
|
190
|
+
this.shadowRoot.querySelector("#inspector").hidden = !entry;
|
|
191
|
+
this.shadowRoot.querySelector("#detail-empty").hidden = !!entry;
|
|
192
|
+
this.shadowRoot.querySelector("#summary").textContent = entry?.summary ?? "";
|
|
193
|
+
this.shadowRoot.querySelector("#metadata").textContent = entry ? `${entry.service} · ${entry.method} · ${entry.pending ? "In progress" : `${entry.durationMs} ms`} · ${new Date(entry.startedAt).toLocaleTimeString()}` : "";
|
|
194
|
+
const outcome = this.shadowRoot.querySelector("#outcome");
|
|
195
|
+
outcome.hidden = !entry || !(entry.error || entry.rpcError || entry.expected || entry.pending);
|
|
196
|
+
outcome.textContent = entry?.rpcError ? `Tool failed despite HTTP ${entry.status}: ${entry.rpcError}` : entry?.error ?? entry?.expected ?? (entry?.pending ? "Waiting for the response…" : "");
|
|
197
|
+
this.shadowRoot.querySelector("#request").code = entry ? formatCallHttp(entry, "request") : "";
|
|
198
|
+
this.shadowRoot.querySelector("#response").code = entry ? entry.pending ? "Response pending" : formatCallHttp(entry, "response") : "";
|
|
105
199
|
}
|
|
106
200
|
}
|
|
107
201
|
CallConsole.register();
|
|
@@ -206,6 +206,8 @@ export class ExplorerActionMenu extends BaseElement {
|
|
|
206
206
|
if (this.itemIdValue && actionId) {
|
|
207
207
|
const item = this.controllerValue?.getState().items.find(entry => entry.id === this.itemIdValue) ?? null;
|
|
208
208
|
const action = this.controllerValue?.getItemActions(this.itemIdValue).find(entry => entry.id === actionId) ?? null;
|
|
209
|
+
if (!action || action.disabled)
|
|
210
|
+
return;
|
|
209
211
|
this.controllerValue?.invokeItemAction(this.itemIdValue, actionId);
|
|
210
212
|
if (item && action) {
|
|
211
213
|
this.dispatchEvent(new CustomEvent(toKebabCase("itemActionInvoked"), {
|
|
@@ -249,7 +251,7 @@ export class ExplorerActionMenu extends BaseElement {
|
|
|
249
251
|
});
|
|
250
252
|
return;
|
|
251
253
|
}
|
|
252
|
-
const menuItems = Array.from(this.shadowRoot.querySelectorAll('[part="menu-item"]'));
|
|
254
|
+
const menuItems = Array.from(this.shadowRoot.querySelectorAll('[part="menu-item"]:not(:disabled)'));
|
|
253
255
|
handleRovingKeydown(keyboardEvent, menuItems, { orientation: "vertical" });
|
|
254
256
|
});
|
|
255
257
|
}
|
|
@@ -269,7 +271,7 @@ export class ExplorerActionMenu extends BaseElement {
|
|
|
269
271
|
}
|
|
270
272
|
const menuMarkup = this.open
|
|
271
273
|
? `<div id="${this.menuId}" part="menu" role="menu">${actions
|
|
272
|
-
.map(action => `<button type="button" part="menu-item" role="menuitem" data-action-id="${escapeHtml(action.id)}">${escapeHtml(action.label)}</button>`)
|
|
274
|
+
.map(action => `<button type="button" part="menu-item" role="menuitem" data-action-id="${escapeHtml(action.id)}" ${action.disabled ? 'disabled aria-disabled="true" tabindex="-1"' : ''}>${escapeHtml(action.label)}</button>`)
|
|
273
275
|
.join("")}</div>`
|
|
274
276
|
: "";
|
|
275
277
|
this.hostEl.innerHTML = `
|
|
@@ -286,12 +288,12 @@ export class ExplorerActionMenu extends BaseElement {
|
|
|
286
288
|
</div>
|
|
287
289
|
`;
|
|
288
290
|
if (this.open) {
|
|
289
|
-
const menuItems = Array.from(this.shadowRoot?.querySelectorAll('[part="menu-item"]') ?? []);
|
|
291
|
+
const menuItems = Array.from(this.shadowRoot?.querySelectorAll('[part="menu-item"]:not(:disabled)') ?? []);
|
|
290
292
|
applyRovingTabindex(menuItems, 0);
|
|
291
293
|
}
|
|
292
294
|
if (justOpened) {
|
|
293
295
|
queueMicrotask(() => {
|
|
294
|
-
this.shadowRoot?.querySelector('[part="menu-item"]')?.focus();
|
|
296
|
+
this.shadowRoot?.querySelector('[part="menu-item"]:not(:disabled)')?.focus();
|
|
295
297
|
});
|
|
296
298
|
return;
|
|
297
299
|
}
|
|
@@ -302,7 +304,7 @@ export class ExplorerActionMenu extends BaseElement {
|
|
|
302
304
|
});
|
|
303
305
|
return;
|
|
304
306
|
}
|
|
305
|
-
if (focusedTrigger) {
|
|
307
|
+
if (focusedTrigger || (focusedActionId && !this.open)) {
|
|
306
308
|
queueMicrotask(() => {
|
|
307
309
|
this.shadowRoot?.querySelector('[part="trigger"]')?.focus();
|
|
308
310
|
});
|
|
@@ -9,6 +9,7 @@ const toKebabCase = (value) => value.replace(/[A-Z]/g, letter => `-${letter.toLo
|
|
|
9
9
|
const elementStyles = `
|
|
10
10
|
:host {
|
|
11
11
|
display: block;
|
|
12
|
+
min-inline-size: 0;
|
|
12
13
|
color: inherit;
|
|
13
14
|
font: inherit;
|
|
14
15
|
}
|
|
@@ -33,14 +34,15 @@ const elementStyles = `
|
|
|
33
34
|
|
|
34
35
|
[part="search"] {
|
|
35
36
|
flex: 1 1 14rem;
|
|
36
|
-
min-width:
|
|
37
|
+
min-width: 0;
|
|
38
|
+
max-width: 100%;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
[part="status"],
|
|
40
42
|
[part="selection-count"] {
|
|
41
43
|
color: var(--boe-token-text-text-secondary, #6f6f6f);
|
|
42
44
|
font-size: 0.85rem;
|
|
43
|
-
|
|
45
|
+
overflow-wrap: anywhere;
|
|
44
46
|
padding-bottom: 0.45rem;
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -54,6 +56,8 @@ const elementStyles = `
|
|
|
54
56
|
|
|
55
57
|
[part="refresh"],
|
|
56
58
|
[part="clear-selection"] {
|
|
59
|
+
max-inline-size: 100%;
|
|
60
|
+
overflow-wrap: anywhere;
|
|
57
61
|
appearance: none;
|
|
58
62
|
font: inherit;
|
|
59
63
|
font-size: 0.88rem;
|
|
@@ -302,6 +302,7 @@ export class FileRequestBuilder extends BaseElement {
|
|
|
302
302
|
if (!host) {
|
|
303
303
|
return;
|
|
304
304
|
}
|
|
305
|
+
const focusedSetting = this.shadowRoot.activeElement?.getAttribute("data-setting-id");
|
|
305
306
|
host.innerHTML = `
|
|
306
307
|
<section part="builder">
|
|
307
308
|
<header part="header">
|
|
@@ -318,6 +319,8 @@ export class FileRequestBuilder extends BaseElement {
|
|
|
318
319
|
</section>
|
|
319
320
|
`;
|
|
320
321
|
this.shadowRoot.querySelectorAll("[data-setting-id]").forEach(input => {
|
|
322
|
+
if (focusedSetting === input.dataset.settingId)
|
|
323
|
+
input.focus({ preventScroll: true });
|
|
321
324
|
input.addEventListener("change", () => {
|
|
322
325
|
const settingId = input.dataset.settingId;
|
|
323
326
|
if (!settingId) {
|