@flamingo-stack/openframe-frontend-core 0.0.225 → 0.0.227

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 (91) hide show
  1. package/dist/{chunk-2QURHTDV.js → chunk-CUBRHI6D.js} +2 -2
  2. package/dist/{chunk-NRJ53MIF.cjs → chunk-E3DB4D43.cjs} +9 -9
  3. package/dist/{chunk-NRJ53MIF.cjs.map → chunk-E3DB4D43.cjs.map} +1 -1
  4. package/dist/{chunk-3YTIV6C5.cjs → chunk-E3WJQQGW.cjs} +7 -7
  5. package/dist/{chunk-3YTIV6C5.cjs.map → chunk-E3WJQQGW.cjs.map} +1 -1
  6. package/dist/{chunk-SAJG77KY.js → chunk-EURLSRHW.js} +2 -2
  7. package/dist/{chunk-IWBDAGZQ.cjs → chunk-HO2VEMEX.cjs} +24 -24
  8. package/dist/{chunk-IWBDAGZQ.cjs.map → chunk-HO2VEMEX.cjs.map} +1 -1
  9. package/dist/{chunk-NHRVPMBU.js → chunk-K252FYE5.js} +3959 -3740
  10. package/dist/chunk-K252FYE5.js.map +1 -0
  11. package/dist/{chunk-5RELSRTS.cjs → chunk-LEM4FLCU.cjs} +10 -10
  12. package/dist/{chunk-5RELSRTS.cjs.map → chunk-LEM4FLCU.cjs.map} +1 -1
  13. package/dist/{chunk-HOQDRQ4M.cjs → chunk-QFC725WU.cjs} +746 -527
  14. package/dist/chunk-QFC725WU.cjs.map +1 -0
  15. package/dist/{chunk-RIEEPMJ6.js → chunk-X3KKG6IU.js} +2 -2
  16. package/dist/{chunk-NUOYDHUM.js → chunk-YE62NF6I.js} +2 -2
  17. package/dist/components/chat/approval-batch-message.d.ts +6 -0
  18. package/dist/components/chat/approval-batch-message.d.ts.map +1 -1
  19. package/dist/components/chat/index.cjs +2 -2
  20. package/dist/components/chat/index.js +1 -1
  21. package/dist/components/contact/index.cjs +3 -3
  22. package/dist/components/contact/index.js +2 -2
  23. package/dist/components/features/index.cjs +10 -2
  24. package/dist/components/features/index.cjs.map +1 -1
  25. package/dist/components/features/index.js +9 -1
  26. package/dist/components/features/notifications/approval-request-notification-tile.d.ts +13 -0
  27. package/dist/components/features/notifications/approval-request-notification-tile.d.ts.map +1 -0
  28. package/dist/components/features/notifications/index.d.ts +4 -1
  29. package/dist/components/features/notifications/index.d.ts.map +1 -1
  30. package/dist/components/features/notifications/notification-drawer.d.ts +3 -1
  31. package/dist/components/features/notifications/notification-drawer.d.ts.map +1 -1
  32. package/dist/components/features/notifications/notification-popups.d.ts +3 -1
  33. package/dist/components/features/notifications/notification-popups.d.ts.map +1 -1
  34. package/dist/components/features/notifications/notification-tile.d.ts +6 -1
  35. package/dist/components/features/notifications/notification-tile.d.ts.map +1 -1
  36. package/dist/components/features/notifications/notifications-context.d.ts +5 -2
  37. package/dist/components/features/notifications/notifications-context.d.ts.map +1 -1
  38. package/dist/components/features/notifications/types.d.ts +30 -0
  39. package/dist/components/features/notifications/types.d.ts.map +1 -1
  40. package/dist/components/index.cjs +87 -77
  41. package/dist/components/index.cjs.map +1 -1
  42. package/dist/components/index.js +14 -4
  43. package/dist/components/index.js.map +1 -1
  44. package/dist/components/navigation/index.cjs +2 -2
  45. package/dist/components/navigation/index.js +1 -1
  46. package/dist/components/onboarding-guides/index.cjs +25 -25
  47. package/dist/components/onboarding-guides/index.js +3 -3
  48. package/dist/components/tickets/index.cjs +64 -64
  49. package/dist/components/tickets/index.js +4 -4
  50. package/dist/components/ui/color-preset-select.d.ts.map +1 -1
  51. package/dist/components/ui/color-swatch.d.ts +7 -0
  52. package/dist/components/ui/color-swatch.d.ts.map +1 -0
  53. package/dist/components/ui/data-table/data-table-body.d.ts +8 -1
  54. package/dist/components/ui/data-table/data-table-body.d.ts.map +1 -1
  55. package/dist/components/ui/data-table/data-table-row.d.ts +4 -2
  56. package/dist/components/ui/data-table/data-table-row.d.ts.map +1 -1
  57. package/dist/components/ui/data-table/index.d.ts +1 -1
  58. package/dist/components/ui/index.cjs +4 -2
  59. package/dist/components/ui/index.cjs.map +1 -1
  60. package/dist/components/ui/index.d.ts +1 -0
  61. package/dist/components/ui/index.d.ts.map +1 -1
  62. package/dist/components/ui/index.js +3 -1
  63. package/dist/components/ui/ticket-status-config-row.d.ts.map +1 -1
  64. package/dist/components/ui/ticket-status-tag.d.ts.map +1 -1
  65. package/dist/index.cjs +12 -2
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.js +11 -1
  68. package/package.json +1 -1
  69. package/src/components/chat/approval-batch-message.tsx +26 -15
  70. package/src/components/features/notifications/approval-request-notification-tile.tsx +118 -0
  71. package/src/components/features/notifications/index.ts +10 -0
  72. package/src/components/features/notifications/notification-drawer.tsx +28 -11
  73. package/src/components/features/notifications/notification-popups.tsx +33 -19
  74. package/src/components/features/notifications/notification-tile.tsx +34 -19
  75. package/src/components/features/notifications/notifications-context.tsx +7 -1
  76. package/src/components/features/notifications/types.ts +50 -0
  77. package/src/components/ui/color-preset-select.tsx +1 -10
  78. package/src/components/ui/color-swatch.tsx +17 -0
  79. package/src/components/ui/data-table/data-table-body.tsx +9 -0
  80. package/src/components/ui/data-table/data-table-row.tsx +24 -3
  81. package/src/components/ui/index.ts +1 -0
  82. package/src/components/ui/modal-v2.tsx +2 -2
  83. package/src/components/ui/ticket-status-config-row.tsx +78 -39
  84. package/src/components/ui/ticket-status-tag.tsx +2 -7
  85. package/src/stories/NotificationDrawer.stories.tsx +148 -1
  86. package/dist/chunk-HOQDRQ4M.cjs.map +0 -1
  87. package/dist/chunk-NHRVPMBU.js.map +0 -1
  88. /package/dist/{chunk-2QURHTDV.js.map → chunk-CUBRHI6D.js.map} +0 -0
  89. /package/dist/{chunk-SAJG77KY.js.map → chunk-EURLSRHW.js.map} +0 -0
  90. /package/dist/{chunk-RIEEPMJ6.js.map → chunk-X3KKG6IU.js.map} +0 -0
  91. /package/dist/{chunk-NUOYDHUM.js.map → chunk-YE62NF6I.js.map} +0 -0
@@ -80,7 +80,7 @@ const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
80
80
  data-state={state}
81
81
  className={cn(
82
82
  "absolute inset-0 bg-black/50 backdrop-blur-[2px] md:backdrop-blur-none",
83
- "duration-200",
83
+ "duration-200 fill-mode-forwards",
84
84
  "data-[state=open]:animate-in data-[state=open]:fade-in-0",
85
85
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
86
86
  // Hold the hidden end-state until unmount so the backdrop doesn't
@@ -101,7 +101,7 @@ const Modal = React.forwardRef<HTMLDivElement, ModalProps>(
101
101
  "bg-ods-bg md:bg-ods-card",
102
102
  "border border-ods-border rounded-md shadow-xl",
103
103
  "p-[var(--spacing-system-xl)] gap-[var(--spacing-system-l)]",
104
- "duration-200",
104
+ "duration-200 fill-mode-forwards",
105
105
  "data-[state=open]:animate-in data-[state=open]:fade-in-0",
106
106
  "data-[state=open]:slide-in-from-bottom-4 md:data-[state=open]:slide-in-from-bottom-0 md:data-[state=open]:zoom-in-95",
107
107
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
@@ -37,12 +37,48 @@ export interface TicketStatusConfigRowProps {
37
37
  isDragging?: boolean
38
38
  }
39
39
 
40
+ let dismissOpenTooltip: (() => void) | null = null
41
+
40
42
  function WithLeftTooltip({ content, children }: { content?: string; children: React.ReactElement }) {
43
+ const [open, setOpen] = React.useState(false)
44
+ const isTouchRef = React.useRef(false)
45
+ const close = React.useCallback(() => setOpen(false), [])
46
+
41
47
  if (!content) return children
48
+
49
+ const toggleFromTouch = () => {
50
+ setOpen(prev => {
51
+ const next = !prev
52
+ if (next) {
53
+ if (dismissOpenTooltip && dismissOpenTooltip !== close) dismissOpenTooltip()
54
+ dismissOpenTooltip = close
55
+ } else if (dismissOpenTooltip === close) {
56
+ dismissOpenTooltip = null
57
+ }
58
+ return next
59
+ })
60
+ }
61
+
42
62
  return (
43
63
  <TooltipProvider delayDuration={150}>
44
- <Tooltip>
45
- <TooltipTrigger asChild>{children}</TooltipTrigger>
64
+ <Tooltip open={open} onOpenChange={setOpen}>
65
+ <TooltipTrigger
66
+ asChild
67
+ onPointerDown={e => {
68
+ isTouchRef.current = e.pointerType === 'touch'
69
+ if (!isTouchRef.current) return
70
+ e.preventDefault()
71
+ toggleFromTouch()
72
+ }}
73
+ onFocus={e => {
74
+ if (isTouchRef.current) e.preventDefault()
75
+ }}
76
+ onClick={e => {
77
+ if (isTouchRef.current) e.preventDefault()
78
+ }}
79
+ >
80
+ {children}
81
+ </TooltipTrigger>
46
82
  <TooltipContent side="left" className="max-w-xs">
47
83
  {content}
48
84
  </TooltipContent>
@@ -75,16 +111,17 @@ export function TicketStatusConfigRow({
75
111
  // Custom rows render as filled pills (no border); system rows take the
76
112
  // page-configured variant (outline/primary). text-h5 already uppercases.
77
113
  const previewVariant: SystemTagVariant | undefined = systemTagVariant ?? (isSystem ? undefined : 'primary')
114
+ const colClass = 'min-w-0 grow basis-[calc(50%-6px)] md:basis-0'
78
115
 
79
116
  return (
80
117
  <div
81
118
  className={cn(
82
- 'flex w-full items-center gap-[var(--spacing-system-m)] rounded-md border border-ods-border bg-ods-card',
119
+ 'flex w-full items-start gap-3 rounded-md border border-ods-border bg-ods-card md:gap-[var(--spacing-system-m)]',
83
120
  'p-[var(--spacing-system-m)]',
84
121
  isDragging && 'opacity-70 shadow-lg',
85
122
  )}
86
123
  >
87
- <div className="flex size-8 shrink-0 items-center justify-center text-ods-text-secondary">
124
+ <div className="flex h-11 w-8 shrink-0 items-center justify-center text-ods-text-secondary md:h-12">
88
125
  {isSystem ? (
89
126
  <DraggerIcon size={24} aria-hidden className="opacity-40" />
90
127
  ) : (
@@ -100,45 +137,47 @@ export function TicketStatusConfigRow({
100
137
  )}
101
138
  </div>
102
139
 
103
- <div className="flex flex-1 min-w-0 flex-col gap-[var(--spacing-system-xxs)]">
104
- <Input
105
- value={name}
106
- onChange={e => onNameChange?.(e.target.value)}
107
- disabled={isSystem}
108
- readOnly={isSystem}
109
- aria-label="Status name"
110
- maxLength={50}
111
- />
112
- </div>
113
-
114
- {showColorPicker ? (
115
- <div className="flex flex-1 min-w-0">
116
- <ColorPresetSelect value={color} presetKey={presetKey} onChange={onColorChange} />
140
+ <div className="flex min-w-0 flex-1 flex-wrap items-start gap-x-3 gap-y-4 md:flex-nowrap md:gap-[var(--spacing-system-m)]">
141
+ <div className={cn('flex flex-col gap-[var(--spacing-system-xxs)]', colClass)}>
142
+ <Input
143
+ value={name}
144
+ onChange={e => onNameChange?.(e.target.value)}
145
+ disabled={isSystem}
146
+ readOnly={isSystem}
147
+ aria-label="Status name"
148
+ maxLength={50}
149
+ />
117
150
  </div>
118
- ) : (
119
- <div aria-hidden className="hidden flex-1 min-w-0 md:block" />
120
- )}
121
151
 
122
- {showColorPicker && isCustomColor ? (
123
- <div className="flex flex-1 min-w-0">
124
- <ColorPickerInput value={color} onChange={next => onColorChange({ color: next, preset: undefined })} />
125
- </div>
126
- ) : (
127
- <div aria-hidden className="hidden flex-1 min-w-0 md:block" />
128
- )}
152
+ {showColorPicker ? (
153
+ <div className={cn('flex', colClass)}>
154
+ <ColorPresetSelect value={color} presetKey={presetKey} onChange={onColorChange} />
155
+ </div>
156
+ ) : (
157
+ <div aria-hidden className={cn('hidden md:block', colClass)} />
158
+ )}
129
159
 
130
- <div className="flex h-12 flex-1 min-w-0 items-center justify-end">
131
- <TicketStatusTag
132
- status={statusKey}
133
- label={name || ' '}
134
- color={previewColor}
135
- variant={previewVariant}
136
- showIcon={isSystem}
137
- className="max-w-full"
138
- />
160
+ {showColorPicker && isCustomColor ? (
161
+ <div className={cn('flex', colClass)}>
162
+ <ColorPickerInput value={color} onChange={next => onColorChange({ color: next, preset: undefined })} />
163
+ </div>
164
+ ) : (
165
+ <div aria-hidden className={cn('hidden md:block', colClass)} />
166
+ )}
167
+
168
+ <div className={cn('flex h-11 items-center justify-start md:h-12 md:justify-end', colClass)}>
169
+ <TicketStatusTag
170
+ status={statusKey}
171
+ label={name || ' '}
172
+ color={previewColor}
173
+ variant={previewVariant}
174
+ showIcon={isSystem}
175
+ className="max-w-full"
176
+ />
177
+ </div>
139
178
  </div>
140
179
 
141
- <div className="flex size-12 shrink-0 items-center justify-center">
180
+ <div className="flex h-11 w-12 shrink-0 items-center justify-center md:h-12">
142
181
  {isSystem ? (
143
182
  <WithLeftTooltip content={systemTooltip}>
144
183
  <button
@@ -159,7 +198,7 @@ export function TicketStatusConfigRow({
159
198
  aria-label="Delete status"
160
199
  disabled={deleteDisabled}
161
200
  onClick={deleteDisabled ? undefined : onDelete}
162
- className="size-12"
201
+ className={cn('size-11 md:size-12', deleteDisabled && 'pointer-events-none')}
163
202
  >
164
203
  <TrashIcon className="text-ods-error"/>
165
204
  </Button>
@@ -2,6 +2,7 @@
2
2
 
3
3
  import React from 'react'
4
4
  import { ActionsMenuDropdown } from './actions-menu'
5
+ import { ColorSwatch } from './color-swatch'
5
6
  import { Tag, type TagProps, tagVariants } from './tag'
6
7
  import { CheckCircleIcon, Chevron02DownIcon } from '../icons-v2-generated'
7
8
  import { cn } from '../../utils/cn'
@@ -257,13 +258,7 @@ export function TicketStatusTag({
257
258
  items: options.map(option => ({
258
259
  id: option.id,
259
260
  label: option.name,
260
- icon: (
261
- <span
262
- className="size-2 shrink-0 rounded-full"
263
- style={{ backgroundColor: option.color }}
264
- aria-hidden
265
- />
266
- ),
261
+ icon: <ColorSwatch color={option.color} />,
267
262
  onClick: () => onSelect(option.id),
268
263
  disabled: isPending,
269
264
  })),
@@ -2,13 +2,17 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
2
  import * as React from 'react';
3
3
  import { Button } from '../components/ui/button';
4
4
  import {
5
+ ADMIN_APPROVAL_REQUEST_CONTEXT_TYPE,
6
+ ApprovalRequestNotificationTile,
5
7
  NotificationDrawer,
6
8
  NotificationPopups,
7
9
  NotificationTile,
8
10
  NotificationsProvider,
11
+ isApprovalNotification,
9
12
  useNotifications,
10
13
  type Notification,
11
14
  type NotificationVariant,
15
+ type RenderNotificationTile,
12
16
  } from '../components/features/notifications';
13
17
  import { Toaster } from '../components/ui/toaster';
14
18
 
@@ -235,9 +239,64 @@ export const DrawerWithSeedData: Story = {
235
239
  * the same tile isn't shown twice. Toggle "Show Notifications" inside the
236
240
  * drawer to disable pop-ups entirely.
237
241
  */
242
+ /** A deliberately long script so the command section overflows and scrolls. */
243
+ const LONG_POWERSHELL = [
244
+ '# Full diagnostic bundle — collect logs, configs and telemetry',
245
+ '$ErrorActionPreference = "Stop"',
246
+ '$stamp = Get-Date -Format "yyyyMMdd_HHmmss"',
247
+ '$out = "C:\\Logs\\diag_$stamp"',
248
+ 'New-Item -ItemType Directory -Path $out -Force | Out-Null',
249
+ '',
250
+ 'Write-Host "Collecting event logs..."',
251
+ 'foreach ($log in "System","Application","Security","Setup") {',
252
+ ' wevtutil epl $log "$out\\$log.evtx"',
253
+ '}',
254
+ '',
255
+ 'Write-Host "Collecting installed software..."',
256
+ 'Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* |',
257
+ ' Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |',
258
+ ' Sort-Object DisplayName |',
259
+ ' Export-Csv "$out\\software.csv" -NoTypeInformation',
260
+ '',
261
+ 'Write-Host "Collecting running services and processes..."',
262
+ 'Get-Service | Export-Csv "$out\\services.csv" -NoTypeInformation',
263
+ 'Get-Process | Select-Object Name, Id, CPU, WorkingSet | Export-Csv "$out\\processes.csv" -NoTypeInformation',
264
+ '',
265
+ 'Write-Host "Collecting network configuration..."',
266
+ 'ipconfig /all > "$out\\ipconfig.txt"',
267
+ 'Get-NetTCPConnection | Export-Csv "$out\\connections.csv" -NoTypeInformation',
268
+ '',
269
+ 'Write-Host "Compressing bundle..."',
270
+ 'Compress-Archive -Path "$out\\*" -DestinationPath "$out.zip" -Force',
271
+ 'Remove-Item -Path $out -Recurse -Force',
272
+ 'Write-Host "Diagnostic bundle ready at $out.zip"',
273
+ ].join('\n');
274
+
275
+ /**
276
+ * Renders approval-request notifications with the dedicated
277
+ * `ApprovalRequestNotificationTile` (collapsible command section + Approve /
278
+ * Reject), falling back to the default tile for everything else.
279
+ */
280
+ const renderApprovalTile: RenderNotificationTile = (n, { onComplete, onSettle, liveDurationMs }) => {
281
+ if (!isApprovalNotification(n)) return undefined;
282
+ return (
283
+ <ApprovalRequestNotificationTile
284
+ notification={n}
285
+ onApprove={(id) => alert(`Approved ${id}`)}
286
+ onReject={(id) => alert(`Rejected ${id}`)}
287
+ onComplete={onComplete}
288
+ onSettle={onSettle}
289
+ liveDurationMs={liveDurationMs}
290
+ />
291
+ );
292
+ };
293
+
238
294
  export const LivePlayground: Story = {
239
295
  render: () => (
240
- <NotificationsProvider onHistoryClick={() => alert('Navigate to /notifications')}>
296
+ <NotificationsProvider
297
+ onHistoryClick={() => alert('Navigate to /notifications')}
298
+ renderTile={renderApprovalTile}
299
+ >
241
300
  <NotificationDrawer />
242
301
  <NotificationPopups />
243
302
  <PlaygroundControls />
@@ -249,6 +308,7 @@ export const LivePlayground: Story = {
249
308
  function PlaygroundControls() {
250
309
  const { addNotification, markAllRead, clear, toggle, notifications, unreadCount, showPopups } =
251
310
  useNotifications();
311
+ const approvalSeq = React.useRef(0);
252
312
 
253
313
  const fire = (variant: NotificationVariant, title: string, description: string) => {
254
314
  addNotification({ variant, title, description });
@@ -263,6 +323,84 @@ function PlaygroundControls() {
263
323
  });
264
324
  };
265
325
 
326
+ const fireApproval = (
327
+ title: string,
328
+ description: string,
329
+ toolCalls: Array<Record<string, unknown>>,
330
+ ) => {
331
+ const n = approvalSeq.current++;
332
+ addNotification({
333
+ variant: 'warning',
334
+ title,
335
+ description,
336
+ meta: {
337
+ contextType: ADMIN_APPROVAL_REQUEST_CONTEXT_TYPE,
338
+ approvalRequestId: `req-${n}`,
339
+ approvalType: 'ADMIN',
340
+ toolCalls: toolCalls.map((tc, i) => ({
341
+ toolExecutionRequestId: `ter-${n}-${i}`,
342
+ requiresApproval: true,
343
+ ...tc,
344
+ })),
345
+ },
346
+ });
347
+ };
348
+
349
+ const fireSingleApproval = () =>
350
+ fireApproval('Tech Required', 'Approval is required to execute the command.', [
351
+ {
352
+ toolName: 'run_command',
353
+ toolTitle: 'Run PowerShell command',
354
+ toolType: 'TACTICAL_RMM',
355
+ toolExplanation:
356
+ 'Collects all events from System, Application, and Security logs for today and exports them to a CSV file at C:\\Logs\\today_logs.csv.',
357
+ toolCallArguments: {
358
+ command:
359
+ '$today = (Get-Date).Date\n$logs = Get-WinEvent -FilterHashtable @{ LogName = "System","Application","Security"; StartTime = $today }\n$logs | Export-Csv -Path "C:\\Logs\\today_logs.csv" -NoTypeInformation',
360
+ },
361
+ },
362
+ ]);
363
+
364
+ const fireBatchApproval = () =>
365
+ fireApproval('Multiple actions need approval', 'Mingo wants to run 3 commands on SRV-DB01.', [
366
+ {
367
+ toolName: 'run_command',
368
+ toolTitle: 'Restart print spooler',
369
+ toolType: 'TACTICAL_RMM',
370
+ toolExplanation: 'Restarts the Spooler service to clear a stuck print queue.',
371
+ toolCallArguments: { command: 'Restart-Service -Name Spooler -Force' },
372
+ },
373
+ {
374
+ toolName: 'run_query',
375
+ toolTitle: 'Query disk usage',
376
+ toolType: 'OPENFRAME',
377
+ toolExplanation: 'Reports free space per logical volume.',
378
+ toolCallArguments: { query: 'SELECT device_id, free_space, size FROM logical_drives;' },
379
+ },
380
+ {
381
+ toolName: 'run_command',
382
+ toolTitle: 'Purge stale temp files',
383
+ toolType: 'TACTICAL_RMM',
384
+ toolExplanation: 'Deletes %TEMP% contents older than 7 days to reclaim space.',
385
+ toolCallArguments: {
386
+ command:
387
+ 'Get-ChildItem $env:TEMP -Recurse | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-7) } | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue',
388
+ },
389
+ },
390
+ ]);
391
+
392
+ const fireLongApproval = () =>
393
+ fireApproval('Tech Required', 'Approval is required to run a diagnostic script.', [
394
+ {
395
+ toolName: 'run_script',
396
+ toolTitle: 'Run full diagnostic bundle',
397
+ toolType: 'TACTICAL_RMM',
398
+ toolExplanation:
399
+ 'Collects event logs, installed software, services, processes and network configuration, then compresses everything into a single uploadable archive.',
400
+ toolCallArguments: { script: LONG_POWERSHELL },
401
+ },
402
+ ]);
403
+
266
404
  return (
267
405
  <div className="flex max-w-2xl flex-col gap-4">
268
406
  <div className="rounded-md border border-ods-border bg-ods-card p-3">
@@ -311,6 +449,15 @@ function PlaygroundControls() {
311
449
  <Button variant="outline" onClick={fireWithDeepLink}>
312
450
  Fire with deep-link
313
451
  </Button>
452
+ <Button variant="warning" onClick={fireSingleApproval}>
453
+ Fire approval
454
+ </Button>
455
+ <Button variant="warning" onClick={fireBatchApproval}>
456
+ Fire batch approval
457
+ </Button>
458
+ <Button variant="warning" onClick={fireLongApproval}>
459
+ Fire long-command approval
460
+ </Button>
314
461
  </div>
315
462
 
316
463
  <div className="flex flex-wrap gap-2">