@flamingo-stack/openframe-frontend-core 0.0.351 → 0.0.352-snapshot.20260701170615

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.
Files changed (117) hide show
  1. package/dist/{chunk-HMUIRZ46.cjs → chunk-3B663UT5.cjs} +222 -165
  2. package/dist/chunk-3B663UT5.cjs.map +1 -0
  3. package/dist/{chunk-UQFTSFIF.cjs → chunk-5AR4XSIK.cjs} +29 -29
  4. package/dist/{chunk-UQFTSFIF.cjs.map → chunk-5AR4XSIK.cjs.map} +1 -1
  5. package/dist/{chunk-MLW25MGY.js → chunk-5Y6G2GKO.js} +3 -3
  6. package/dist/{chunk-EKU6D26E.js → chunk-776NIQQ6.js} +6 -6
  7. package/dist/{chunk-YBL3JURC.js → chunk-BAPR6IQV.js} +5 -5
  8. package/dist/{chunk-VY6AAUCK.js → chunk-CDPGUKPU.js} +2 -2
  9. package/dist/{chunk-NEIOYJIE.cjs → chunk-D4TPL6T4.cjs} +15 -15
  10. package/dist/{chunk-NEIOYJIE.cjs.map → chunk-D4TPL6T4.cjs.map} +1 -1
  11. package/dist/{chunk-YIFJJCFB.js → chunk-EQQZLZZH.js} +4 -4
  12. package/dist/{chunk-RD3HIB25.cjs → chunk-GPX5I7FT.cjs} +2 -2
  13. package/dist/{chunk-FPAF4JHM.js.map → chunk-GPX5I7FT.cjs.map} +1 -1
  14. package/dist/{chunk-46Z3O6SN.cjs → chunk-HAFY32LW.cjs} +5 -5
  15. package/dist/{chunk-46Z3O6SN.cjs.map → chunk-HAFY32LW.cjs.map} +1 -1
  16. package/dist/{chunk-VZ7TICMR.cjs → chunk-HWFFUT6G.cjs} +40 -40
  17. package/dist/{chunk-VZ7TICMR.cjs.map → chunk-HWFFUT6G.cjs.map} +1 -1
  18. package/dist/{chunk-NIRMBPFP.cjs → chunk-IVL6FGM6.cjs} +19 -19
  19. package/dist/{chunk-NIRMBPFP.cjs.map → chunk-IVL6FGM6.cjs.map} +1 -1
  20. package/dist/{chunk-FPAF4JHM.js → chunk-JGAAUUD7.js} +2 -2
  21. package/dist/chunk-JGAAUUD7.js.map +1 -0
  22. package/dist/{chunk-A6YFD2SK.js → chunk-OKGXLXDW.js} +174 -117
  23. package/dist/chunk-OKGXLXDW.js.map +1 -0
  24. package/dist/{chunk-63ISTNQW.cjs → chunk-P56AC6I5.cjs} +31 -31
  25. package/dist/{chunk-63ISTNQW.cjs.map → chunk-P56AC6I5.cjs.map} +1 -1
  26. package/dist/{chunk-4WVVMKMC.js → chunk-POLYFLWF.js} +5 -5
  27. package/dist/{chunk-JKJO7HVH.cjs → chunk-RYROZ7HM.cjs} +3 -3
  28. package/dist/{chunk-JKJO7HVH.cjs.map → chunk-RYROZ7HM.cjs.map} +1 -1
  29. package/dist/{chunk-QGBJKB6V.cjs → chunk-TWVF3QU5.cjs} +39 -39
  30. package/dist/{chunk-QGBJKB6V.cjs.map → chunk-TWVF3QU5.cjs.map} +1 -1
  31. package/dist/{chunk-KYCZ4ISB.js → chunk-U5MQW3PH.js} +2 -2
  32. package/dist/{chunk-XZVVLO4V.cjs → chunk-W3CCNLBL.cjs} +12 -12
  33. package/dist/{chunk-XZVVLO4V.cjs.map → chunk-W3CCNLBL.cjs.map} +1 -1
  34. package/dist/{chunk-DJZ64AF6.js → chunk-XJQNOT4Z.js} +2 -2
  35. package/dist/{chunk-TH3HPNMO.cjs → chunk-XKRR5GIV.cjs} +70 -70
  36. package/dist/{chunk-TH3HPNMO.cjs.map → chunk-XKRR5GIV.cjs.map} +1 -1
  37. package/dist/{chunk-JBWB3U3P.js → chunk-YGCWTL7E.js} +2 -2
  38. package/dist/{chunk-5F45BY24.js → chunk-YI5435S6.js} +3 -3
  39. package/dist/{chunk-BMQ5CBFD.cjs → chunk-YL2YXSRI.cjs} +73 -73
  40. package/dist/{chunk-BMQ5CBFD.cjs.map → chunk-YL2YXSRI.cjs.map} +1 -1
  41. package/dist/{chunk-GJZL72ON.cjs → chunk-Z22AMCZL.cjs} +7 -7
  42. package/dist/{chunk-GJZL72ON.cjs.map → chunk-Z22AMCZL.cjs.map} +1 -1
  43. package/dist/{chunk-WB2EWYSF.js → chunk-ZAKU2MOI.js} +3 -3
  44. package/dist/{chunk-Q3VK7WI2.js → chunk-ZYB2QBNU.js} +6 -6
  45. package/dist/components/case-studies/index.cjs +9 -9
  46. package/dist/components/case-studies/index.js +3 -3
  47. package/dist/components/chat/approval-batch-message.d.ts +7 -1
  48. package/dist/components/chat/approval-batch-message.d.ts.map +1 -1
  49. package/dist/components/chat/approval-request-message.d.ts.map +1 -1
  50. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  51. package/dist/components/chat/index.cjs +3 -3
  52. package/dist/components/chat/index.js +2 -2
  53. package/dist/components/chat/tool-call-blocks.d.ts.map +1 -1
  54. package/dist/components/chat/tool-execution-display.d.ts.map +1 -1
  55. package/dist/components/chat/types/component.types.d.ts +6 -0
  56. package/dist/components/chat/types/component.types.d.ts.map +1 -1
  57. package/dist/components/contact/index.cjs +4 -4
  58. package/dist/components/contact/index.js +3 -3
  59. package/dist/components/docs/index.cjs +6 -6
  60. package/dist/components/docs/index.js +5 -5
  61. package/dist/components/embeds/index.cjs +4 -4
  62. package/dist/components/embeds/index.js +3 -3
  63. package/dist/components/faq/index.cjs +5 -5
  64. package/dist/components/faq/index.js +4 -4
  65. package/dist/components/features/index.cjs +3 -3
  66. package/dist/components/features/index.js +2 -2
  67. package/dist/components/help-center-pages/index.cjs +22 -22
  68. package/dist/components/help-center-pages/index.js +13 -13
  69. package/dist/components/index.cjs +124 -124
  70. package/dist/components/index.js +11 -11
  71. package/dist/components/navigation/index.cjs +3 -3
  72. package/dist/components/navigation/index.js +2 -2
  73. package/dist/components/onboarding-guides/index.cjs +7 -7
  74. package/dist/components/onboarding-guides/index.js +6 -6
  75. package/dist/components/related-content/index.cjs +5 -5
  76. package/dist/components/related-content/index.js +4 -4
  77. package/dist/components/tickets/index.cjs +6 -6
  78. package/dist/components/tickets/index.js +5 -5
  79. package/dist/components/ui/index.cjs +3 -3
  80. package/dist/components/ui/index.js +2 -2
  81. package/dist/hooks/index.cjs +2 -2
  82. package/dist/hooks/index.js +1 -1
  83. package/dist/index.cjs +3 -3
  84. package/dist/index.js +2 -2
  85. package/dist/utils/index.cjs +1 -1
  86. package/dist/utils/index.cjs.map +1 -1
  87. package/dist/utils/index.js +1 -1
  88. package/dist/utils/index.js.map +1 -1
  89. package/dist/utils/platform-config.d.ts.map +1 -1
  90. package/package.json +1 -1
  91. package/src/components/chat/approval-batch-message.tsx +82 -27
  92. package/src/components/chat/approval-request-message.tsx +27 -19
  93. package/src/components/chat/chat-message-enhanced.tsx +3 -0
  94. package/src/components/chat/tool-call-blocks.tsx +17 -6
  95. package/src/components/chat/tool-execution-display.tsx +23 -8
  96. package/src/components/chat/types/component.types.ts +6 -0
  97. package/src/stories/ApprovalBatchMessage.stories.tsx +169 -0
  98. package/src/stories/ApprovalBatchMessageClient.stories.tsx +172 -0
  99. package/src/stories/ApprovalRequestMessage.stories.tsx +95 -0
  100. package/src/stories/ToolExecutionDisplay.stories.tsx +1 -1
  101. package/src/stories/ToolExecutionDisplayClient.stories.tsx +64 -0
  102. package/src/utils/platform-config.tsx +4 -1
  103. package/dist/chunk-A6YFD2SK.js.map +0 -1
  104. package/dist/chunk-HMUIRZ46.cjs.map +0 -1
  105. package/dist/chunk-RD3HIB25.cjs.map +0 -1
  106. /package/dist/{chunk-MLW25MGY.js.map → chunk-5Y6G2GKO.js.map} +0 -0
  107. /package/dist/{chunk-EKU6D26E.js.map → chunk-776NIQQ6.js.map} +0 -0
  108. /package/dist/{chunk-YBL3JURC.js.map → chunk-BAPR6IQV.js.map} +0 -0
  109. /package/dist/{chunk-VY6AAUCK.js.map → chunk-CDPGUKPU.js.map} +0 -0
  110. /package/dist/{chunk-YIFJJCFB.js.map → chunk-EQQZLZZH.js.map} +0 -0
  111. /package/dist/{chunk-4WVVMKMC.js.map → chunk-POLYFLWF.js.map} +0 -0
  112. /package/dist/{chunk-KYCZ4ISB.js.map → chunk-U5MQW3PH.js.map} +0 -0
  113. /package/dist/{chunk-DJZ64AF6.js.map → chunk-XJQNOT4Z.js.map} +0 -0
  114. /package/dist/{chunk-JBWB3U3P.js.map → chunk-YGCWTL7E.js.map} +0 -0
  115. /package/dist/{chunk-5F45BY24.js.map → chunk-YI5435S6.js.map} +0 -0
  116. /package/dist/{chunk-WB2EWYSF.js.map → chunk-ZAKU2MOI.js.map} +0 -0
  117. /package/dist/{chunk-Q3VK7WI2.js.map → chunk-ZYB2QBNU.js.map} +0 -0
@@ -0,0 +1,169 @@
1
+ import type { Meta, StoryObj } from "@storybook/nextjs-vite";
2
+ import type React from "react";
3
+
4
+ import { ApprovalBatchMessage } from "../components/chat/approval-batch-message";
5
+ import type {
6
+ ApprovalBatchData,
7
+ ApprovalBatchExecutionState,
8
+ PendingToolCallData,
9
+ } from "../components/chat/types";
10
+
11
+ /**
12
+ * The "Command Block" from Figma (open-design-system, node 1092-2807).
13
+ *
14
+ * A single command/tool call the AI wants to run, rendered as an approvable
15
+ * card: a command title line, an expandable body with the call arguments
16
+ * (RunAsUser, timeoutSeconds, …) and — once executed — a Result block. The
17
+ * footer flips between Approve/Reject buttons (pending) and a resolved status
18
+ * tag ("Approved / Rejected / Cancelled by {name}").
19
+ *
20
+ * Click a row to expand/collapse its body.
21
+ */
22
+
23
+ const LONG_COMMAND = `Get-CimInstance Win32_Process |
24
+ Select-Object ProcessId, Name, Path, CommandLine |
25
+ Where-Object { $_.Path -like 'C:\\Users\\Public\\*' }`;
26
+
27
+ const RESULT = `pid | name | path | cmdline
28
+ 4821 | suspicious.exe | C:\\Users\\Public\\suspicious.exe | suspicious.exe --hidden --connect 185.220.101.45`;
29
+
30
+ const REQUEST_ID = "req-1";
31
+
32
+ const toolCall: PendingToolCallData = {
33
+ toolExecutionRequestId: REQUEST_ID,
34
+ toolName: "run_script",
35
+ toolTitle: "Run Script",
36
+ toolExplanation:
37
+ "Runs a diagnostic script on the endpoint to inspect running processes.",
38
+ toolType: "TACTICAL_RMM",
39
+ requiresApproval: true,
40
+ approvalType: "ADMIN",
41
+ toolCallArguments: {
42
+ command: LONG_COMMAND,
43
+ RunAsUser: "False",
44
+ timeoutSeconds: 60,
45
+ },
46
+ };
47
+
48
+ const makeData = (
49
+ executions?: Record<string, ApprovalBatchExecutionState>,
50
+ ): ApprovalBatchData => ({
51
+ approvalRequestId: "batch-1",
52
+ approvalType: "ADMIN",
53
+ toolCalls: [toolCall],
54
+ executions,
55
+ });
56
+
57
+ const executingData = makeData({ [REQUEST_ID]: { status: "executing" } });
58
+ const doneData = makeData({
59
+ [REQUEST_ID]: { status: "done", result: RESULT, success: true },
60
+ });
61
+
62
+ const constrainedDecorator =
63
+ (width?: number) => (Story: React.ComponentType) => (
64
+ <div style={{ maxWidth: width ?? 400, background: "var(--color-bg)" }}>
65
+ <Story />
66
+ </div>
67
+ );
68
+
69
+ const meta = {
70
+ title: "Chat/Admin/ApprovalBatchMessage",
71
+ component: ApprovalBatchMessage,
72
+ tags: ["autodocs"],
73
+ parameters: {
74
+ docs: {
75
+ description: {
76
+ component:
77
+ "Command Block (Figma node 1092-2807). Approvable tool-call card with pending / approved / rejected / cancelled states, an expandable body of call arguments, and a Result block after execution.",
78
+ },
79
+ },
80
+ },
81
+ decorators: [constrainedDecorator()],
82
+ } satisfies Meta<typeof ApprovalBatchMessage>;
83
+
84
+ export default meta;
85
+ type Story = StoryObj<typeof meta>;
86
+
87
+ /** Pending — Approve / Reject buttons shown. Click the row to expand args. */
88
+ export const Pending: Story = {
89
+ args: {
90
+ data: makeData(),
91
+ status: "pending",
92
+ onApprove: () => {},
93
+ onReject: () => {},
94
+ },
95
+ };
96
+
97
+ /** Approved and still executing — grey loader on the row, no result yet. */
98
+ export const ApprovedExecuting: Story = {
99
+ args: {
100
+ data: executingData,
101
+ status: "approved",
102
+ resolvedByName: "Michael Johnson",
103
+ },
104
+ };
105
+
106
+ /** Approved and finished — green check + expandable Result block. */
107
+ export const ApprovedDone: Story = {
108
+ args: {
109
+ data: doneData,
110
+ status: "approved",
111
+ resolvedByName: "Michael Johnson",
112
+ },
113
+ };
114
+
115
+ /** Rejected by a user — red status tag, no execution. */
116
+ export const Rejected: Story = {
117
+ args: {
118
+ data: makeData(),
119
+ status: "rejected",
120
+ resolvedByName: "Michael Johnson",
121
+ },
122
+ };
123
+
124
+ /** Cancelled — grey status tag, no execution. */
125
+ export const Cancelled: Story = {
126
+ args: {
127
+ data: makeData(),
128
+ status: "cancelled",
129
+ resolvedByName: "Michael Johnson",
130
+ },
131
+ };
132
+
133
+ /**
134
+ * All states side by side — mirrors the Figma "Command Blocks" board so the
135
+ * full set can be reviewed at a glance.
136
+ */
137
+ export const AllStates: Story = {
138
+ decorators: [constrainedDecorator(420)],
139
+ render: () => (
140
+ <div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
141
+ <ApprovalBatchMessage
142
+ data={makeData()}
143
+ status="pending"
144
+ onApprove={() => {}}
145
+ onReject={() => {}}
146
+ />
147
+ <ApprovalBatchMessage
148
+ data={executingData}
149
+ status="approved"
150
+ resolvedByName="Michael Johnson"
151
+ />
152
+ <ApprovalBatchMessage
153
+ data={doneData}
154
+ status="approved"
155
+ resolvedByName="Michael Johnson"
156
+ />
157
+ <ApprovalBatchMessage
158
+ data={makeData()}
159
+ status="rejected"
160
+ resolvedByName="Michael Johnson"
161
+ />
162
+ <ApprovalBatchMessage
163
+ data={makeData()}
164
+ status="cancelled"
165
+ resolvedByName="Michael Johnson"
166
+ />
167
+ </div>
168
+ ),
169
+ };
@@ -0,0 +1,172 @@
1
+ import type { Meta, StoryObj } from "@storybook/nextjs-vite";
2
+ import type React from "react";
3
+
4
+ import { ApprovalBatchMessage } from "../components/chat/approval-batch-message";
5
+ import type {
6
+ ApprovalBatchData,
7
+ ApprovalBatchExecutionState,
8
+ PendingToolCallData,
9
+ } from "../components/chat/types";
10
+
11
+ /**
12
+ * CLIENT (Fae) variant of the Command Block — Figma node 1092-2807.
13
+ *
14
+ * Same component and props as the Admin card, driven by `assistantType="fae"`.
15
+ * Differences vs Admin: no tool icon next to the command, no footer divider,
16
+ * and a single full-text status pill ("Approved by Michael Johnson") instead
17
+ * of a compact tag + separate "by {name}".
18
+ */
19
+
20
+ const LONG_COMMAND = `Get-CimInstance Win32_Process |
21
+ Select-Object ProcessId, Name, Path, CommandLine |
22
+ Where-Object { $_.Path -like 'C:\\Users\\Public\\*' }`;
23
+
24
+ const RESULT = `pid | name | path | cmdline
25
+ 4821 | suspicious.exe | C:\\Users\\Public\\suspicious.exe | suspicious.exe --hidden --connect 185.220.101.45`;
26
+
27
+ const REQUEST_ID = "req-1";
28
+
29
+ const toolCall: PendingToolCallData = {
30
+ toolExecutionRequestId: REQUEST_ID,
31
+ toolName: "run_script",
32
+ toolTitle: "Run Script",
33
+ toolType: "TACTICAL_RMM",
34
+ requiresApproval: true,
35
+ approvalType: "CLIENT",
36
+ toolCallArguments: {
37
+ command: LONG_COMMAND,
38
+ RunAsUser: "False",
39
+ timeoutSeconds: 60,
40
+ },
41
+ };
42
+
43
+ const makeData = (
44
+ executions?: Record<string, ApprovalBatchExecutionState>,
45
+ ): ApprovalBatchData => ({
46
+ approvalRequestId: "batch-1",
47
+ approvalType: "CLIENT",
48
+ toolCalls: [toolCall],
49
+ executions,
50
+ });
51
+
52
+ const executingData = makeData({ [REQUEST_ID]: { status: "executing" } });
53
+ const doneData = makeData({
54
+ [REQUEST_ID]: { status: "done", result: RESULT, success: true },
55
+ });
56
+
57
+ /**
58
+ * The assistant's message text that precedes the command block in the real
59
+ * chat (Figma "Command description text."). It is NOT part of the component —
60
+ * shown here only so the story matches the Figma frame.
61
+ */
62
+ const CommandHeading = () => (
63
+ <p className="text-h4 text-ods-text-primary mb-[var(--spacing-system-xxs)]">
64
+ Command description text.
65
+ </p>
66
+ );
67
+
68
+ const constrainedDecorator =
69
+ (width?: number) => (Story: React.ComponentType) => (
70
+ <div style={{ maxWidth: width ?? 400, background: "var(--color-bg)" }}>
71
+ <CommandHeading />
72
+ <Story />
73
+ </div>
74
+ );
75
+
76
+ const plainDecorator =
77
+ (width?: number) => (Story: React.ComponentType) => (
78
+ <div style={{ maxWidth: width ?? 400, background: "var(--color-bg)" }}>
79
+ <Story />
80
+ </div>
81
+ );
82
+
83
+ const meta = {
84
+ title: "Chat/Client/ApprovalBatchMessage",
85
+ component: ApprovalBatchMessage,
86
+ tags: ["autodocs"],
87
+ args: { assistantType: "fae" },
88
+ parameters: {
89
+ docs: {
90
+ description: {
91
+ component:
92
+ "CLIENT (Fae) Command Block — no tool icon, no divider, full-text status pill. Same component/props as Admin, gated by assistantType='fae' (Figma 1092-2807).",
93
+ },
94
+ },
95
+ },
96
+ decorators: [constrainedDecorator()],
97
+ } satisfies Meta<typeof ApprovalBatchMessage>;
98
+
99
+ export default meta;
100
+ type Story = StoryObj<typeof meta>;
101
+
102
+ /** Pending — Approve / Reject buttons. Click the row to expand args. */
103
+ export const Pending: Story = {
104
+ args: {
105
+ data: makeData(),
106
+ status: "pending",
107
+ onApprove: () => {},
108
+ onReject: () => {},
109
+ },
110
+ };
111
+
112
+ /** Approved and still executing — grey loader on the row, no result yet. */
113
+ export const ApprovedExecuting: Story = {
114
+ args: {
115
+ data: executingData,
116
+ status: "approved",
117
+ resolvedByName: "Michael Johnson",
118
+ },
119
+ };
120
+
121
+ /** Approved and finished — green check + expandable Result block. */
122
+ export const ApprovedDone: Story = {
123
+ args: {
124
+ data: doneData,
125
+ status: "approved",
126
+ resolvedByName: "Michael Johnson",
127
+ },
128
+ };
129
+
130
+ /** Rejected by a user — full-text red status pill. */
131
+ export const Rejected: Story = {
132
+ args: {
133
+ data: makeData(),
134
+ status: "rejected",
135
+ resolvedByName: "Michael Johnson",
136
+ },
137
+ };
138
+
139
+ /** Cancelled — full-text grey status pill. */
140
+ export const Cancelled: Story = {
141
+ args: {
142
+ data: makeData(),
143
+ status: "cancelled",
144
+ resolvedByName: "Michael Johnson",
145
+ },
146
+ };
147
+
148
+ /**
149
+ * All states side by side — mirrors the Figma CLIENT "Command Blocks" board.
150
+ */
151
+ export const AllStates: Story = {
152
+ decorators: [plainDecorator(420)],
153
+ render: () => {
154
+ const states = [
155
+ { data: makeData(), status: "pending" as const, onApprove: () => {}, onReject: () => {} },
156
+ { data: executingData, status: "approved" as const, resolvedByName: "Michael Johnson" },
157
+ { data: doneData, status: "approved" as const, resolvedByName: "Michael Johnson" },
158
+ { data: makeData(), status: "rejected" as const, resolvedByName: "Michael Johnson" },
159
+ { data: makeData(), status: "cancelled" as const, resolvedByName: "Michael Johnson" },
160
+ ];
161
+ return (
162
+ <div style={{ display: "flex", flexDirection: "column", gap: 32 }}>
163
+ {states.map((s, i) => (
164
+ <div key={i}>
165
+ <CommandHeading />
166
+ <ApprovalBatchMessage assistantType="fae" {...s} />
167
+ </div>
168
+ ))}
169
+ </div>
170
+ );
171
+ },
172
+ };
@@ -0,0 +1,95 @@
1
+ import type { Meta, StoryObj } from "@storybook/nextjs-vite";
2
+ import type React from "react";
3
+
4
+ import { ApprovalRequestMessage } from "../components/chat/approval-request-message";
5
+ import type { ApprovalRequestData } from "../components/chat/types";
6
+
7
+ /**
8
+ * Single-command approval card (the legacy, non-batch variant of the Figma
9
+ * "Command Block"). Renders a command bar, an optional structured field list
10
+ * or explanation, and an Approve/Reject footer that flips to an
11
+ * Approved/Rejected status tag once resolved.
12
+ *
13
+ * Newer surfaces use `ApprovalBatchMessage` (see the ApprovalBatchMessage
14
+ * story) which additionally tracks per-tool execution + results.
15
+ */
16
+
17
+ const LONG_COMMAND = `Get-CimInstance Win32_Process |
18
+ Select-Object ProcessId, Name, Path, CommandLine |
19
+ Where-Object { $_.Path -like 'C:\\Users\\Public\\*' }`;
20
+
21
+ const baseData: ApprovalRequestData = {
22
+ command: LONG_COMMAND,
23
+ requestId: "req-1",
24
+ approvalType: "ADMIN",
25
+ fields: [
26
+ { label: "Tool", value: "Tactical RMM" },
27
+ { label: "RunAsUser", value: "False" },
28
+ { label: "timeoutSeconds", value: "60" },
29
+ ],
30
+ };
31
+
32
+ const constrainedDecorator =
33
+ (width?: number) => (Story: React.ComponentType) => (
34
+ <div style={{ maxWidth: width ?? 400, background: "var(--color-bg)" }}>
35
+ <Story />
36
+ </div>
37
+ );
38
+
39
+ const meta = {
40
+ title: "Chat/Admin/ApprovalRequestMessage",
41
+ component: ApprovalRequestMessage,
42
+ tags: ["autodocs"],
43
+ parameters: {
44
+ docs: {
45
+ description: {
46
+ component:
47
+ "Single-command approval card — the legacy variant of the Figma Command Block. Prefer ApprovalBatchMessage for new work.",
48
+ },
49
+ },
50
+ },
51
+ decorators: [constrainedDecorator()],
52
+ } satisfies Meta<typeof ApprovalRequestMessage>;
53
+
54
+ export default meta;
55
+ type Story = StoryObj<typeof meta>;
56
+
57
+ /** Pending — Approve / Reject buttons shown. */
58
+ export const Pending: Story = {
59
+ args: {
60
+ data: baseData,
61
+ status: "pending",
62
+ onApprove: () => {},
63
+ onReject: () => {},
64
+ },
65
+ };
66
+
67
+ /** Approved — green status tag. */
68
+ export const Approved: Story = {
69
+ args: { data: baseData, status: "approved" },
70
+ };
71
+
72
+ /** Rejected — red status tag. */
73
+ export const Rejected: Story = {
74
+ args: { data: baseData, status: "rejected" },
75
+ };
76
+
77
+ /** Cancelled — grey status tag. */
78
+ export const Cancelled: Story = {
79
+ args: { data: baseData, status: "cancelled" },
80
+ };
81
+
82
+ /** Explanation prose instead of a structured field list. */
83
+ export const WithExplanation: Story = {
84
+ args: {
85
+ data: {
86
+ command: LONG_COMMAND,
87
+ requestId: "req-2",
88
+ explanation:
89
+ "This runs a read-only diagnostic to inspect processes launched from the public folder. It does not modify the endpoint.",
90
+ },
91
+ status: "pending",
92
+ onApprove: () => {},
93
+ onReject: () => {},
94
+ },
95
+ };
@@ -52,7 +52,7 @@ const constrainedDecorator =
52
52
  );
53
53
 
54
54
  const meta = {
55
- title: "Chat/ToolExecutionDisplay",
55
+ title: "Chat/Admin/ToolExecutionDisplay",
56
56
  component: ToolExecutionDisplay,
57
57
  tags: ["autodocs"],
58
58
  parameters: {
@@ -0,0 +1,64 @@
1
+ import type { Meta, StoryObj } from "@storybook/nextjs-vite";
2
+ import type React from "react";
3
+
4
+ import { ToolExecutionDisplay } from "../components/chat/tool-execution-display";
5
+ import type { ToolExecutionData } from "../components/chat/types";
6
+
7
+ /**
8
+ * CLIENT (Fae) variant of the standalone tool-execution card. Same component
9
+ * and props as the Admin card, gated by `assistantType="fae"` — the only
10
+ * visual difference is that the tool icon next to the command is hidden.
11
+ */
12
+
13
+ const executingMessage: ToolExecutionData = {
14
+ type: "EXECUTING_TOOL",
15
+ integratedToolType: "TACTICAL_RMM",
16
+ toolFunction: "run_script",
17
+ parameters: { RunAsUser: "False", timeoutSeconds: 60 },
18
+ };
19
+
20
+ const executedSuccessMessage: ToolExecutionData = {
21
+ type: "EXECUTED_TOOL",
22
+ integratedToolType: "TACTICAL_RMM",
23
+ toolFunction: "run_script",
24
+ parameters: { RunAsUser: "False", timeoutSeconds: 60 },
25
+ result: `pid | name | path | cmdline
26
+ 4821 | suspicious.exe | C:\\Users\\Public\\suspicious.exe | suspicious.exe --hidden --connect 185.220.101.45`,
27
+ success: true,
28
+ };
29
+
30
+ const constrainedDecorator =
31
+ (width?: number) => (Story: React.ComponentType) => (
32
+ <div style={{ maxWidth: width ?? 400, background: "var(--color-bg)" }}>
33
+ <Story />
34
+ </div>
35
+ );
36
+
37
+ const meta = {
38
+ title: "Chat/Client/ToolExecutionDisplay",
39
+ component: ToolExecutionDisplay,
40
+ tags: ["autodocs"],
41
+ args: { assistantType: "fae" },
42
+ parameters: {
43
+ docs: {
44
+ description: {
45
+ component:
46
+ "CLIENT (Fae) tool-execution card — no tool icon. Same component/props as Admin, gated by assistantType='fae'.",
47
+ },
48
+ },
49
+ },
50
+ decorators: [constrainedDecorator()],
51
+ } satisfies Meta<typeof ToolExecutionDisplay>;
52
+
53
+ export default meta;
54
+ type Story = StoryObj<typeof meta>;
55
+
56
+ /** Collapsed, executing — spinner + 2-line preview, no tool icon. */
57
+ export const CollapsedExecuting: Story = {
58
+ args: { message: executingMessage },
59
+ };
60
+
61
+ /** Collapsed, success — green check, no tool icon. */
62
+ export const CollapsedSuccess: Story = {
63
+ args: { message: executedSuccessMessage },
64
+ };
@@ -199,7 +199,10 @@ export function getPlatformIconComponent(platformName: string, className: string
199
199
  case 'openframe':
200
200
  return <OpenFrameLogo className={className} />;
201
201
  case 'openmsp':
202
- return <OpenmspLogo className={className} color="#f1f1f1" />;
202
+ // `OpenmspLogo` ignores `color`; it uses the three bubble props. On a dark
203
+ // surface the default black front-bubble vanishes — use the canonical dark
204
+ // treatment (matches getPlatformIcon above + every hub call-site).
205
+ return <OpenmspLogo className={className} frontBubbleColor="#f1f1f1" innerFrontBubbleColor="#000000" backBubbleColor="#FFC008" />;
203
206
  case 'flamingo':
204
207
  case 'flamingo-teaser':
205
208
  return <FlamingoLogo className={`${className} text-white`} />;