@flamingo-stack/openframe-frontend-core 0.0.516 → 0.0.517-1651.4264.1

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 (98) hide show
  1. package/dist/{chunk-NG7ZMEYW.cjs → chunk-2LMIHPQH.cjs} +4 -4
  2. package/dist/{chunk-NG7ZMEYW.cjs.map → chunk-2LMIHPQH.cjs.map} +1 -1
  3. package/dist/{chunk-SIMZ3VS2.js → chunk-45TSVW73.js} +2 -2
  4. package/dist/{chunk-3XHAX6MO.cjs → chunk-476N4NBC.cjs} +26 -26
  5. package/dist/{chunk-3XHAX6MO.cjs.map → chunk-476N4NBC.cjs.map} +1 -1
  6. package/dist/{chunk-ARTBN7XU.js → chunk-A5WEANTA.js} +2 -2
  7. package/dist/{chunk-BVBY7UMD.cjs → chunk-ARB3MVHH.cjs} +47 -3
  8. package/dist/chunk-ARB3MVHH.cjs.map +1 -0
  9. package/dist/{chunk-KXB6PGWV.js → chunk-CJ55TI4A.js} +4 -4
  10. package/dist/{chunk-UIIMQTTL.cjs → chunk-CV4IMEEH.cjs} +37 -37
  11. package/dist/{chunk-UIIMQTTL.cjs.map → chunk-CV4IMEEH.cjs.map} +1 -1
  12. package/dist/{chunk-FMZX2FOK.cjs → chunk-GWS2J3VC.cjs} +31 -31
  13. package/dist/{chunk-FMZX2FOK.cjs.map → chunk-GWS2J3VC.cjs.map} +1 -1
  14. package/dist/{chunk-FLI5RMO4.js → chunk-GXSKS5RO.js} +2 -2
  15. package/dist/{chunk-ZWTIHBXS.cjs → chunk-HNWJSFEV.cjs} +3 -3
  16. package/dist/{chunk-ZWTIHBXS.cjs.map → chunk-HNWJSFEV.cjs.map} +1 -1
  17. package/dist/{chunk-CALVHRRU.cjs → chunk-HOPPNUGS.cjs} +5 -5
  18. package/dist/{chunk-CALVHRRU.cjs.map → chunk-HOPPNUGS.cjs.map} +1 -1
  19. package/dist/{chunk-W5TUW7US.js → chunk-I75L6RSN.js} +2 -2
  20. package/dist/{chunk-5JLSIN72.cjs → chunk-J4C4IY2F.cjs} +9 -9
  21. package/dist/{chunk-5JLSIN72.cjs.map → chunk-J4C4IY2F.cjs.map} +1 -1
  22. package/dist/{chunk-SIFO7F7J.js → chunk-J6TFTLXF.js} +2 -2
  23. package/dist/{chunk-2T356SFJ.cjs → chunk-KG52CG6Y.cjs} +14 -14
  24. package/dist/{chunk-2T356SFJ.cjs.map → chunk-KG52CG6Y.cjs.map} +1 -1
  25. package/dist/{chunk-4GSNSWXD.cjs → chunk-N2LZPULX.cjs} +11 -11
  26. package/dist/{chunk-4GSNSWXD.cjs.map → chunk-N2LZPULX.cjs.map} +1 -1
  27. package/dist/{chunk-4XFAIQMV.js → chunk-O3CJ6IWP.js} +2 -2
  28. package/dist/{chunk-6IQKCE6Q.js → chunk-OCNHD5XM.js} +6 -6
  29. package/dist/{chunk-YR3YLAGA.js → chunk-QRAGH5CS.js} +2 -2
  30. package/dist/{chunk-XNC2JU6D.cjs → chunk-R7JZC5RX.cjs} +7 -7
  31. package/dist/{chunk-XNC2JU6D.cjs.map → chunk-R7JZC5RX.cjs.map} +1 -1
  32. package/dist/{chunk-CI2NKT45.cjs → chunk-SXWPJHP7.cjs} +26 -26
  33. package/dist/{chunk-CI2NKT45.cjs.map → chunk-SXWPJHP7.cjs.map} +1 -1
  34. package/dist/{chunk-FTA3OFFU.cjs → chunk-U5ZE22FV.cjs} +61 -61
  35. package/dist/{chunk-FTA3OFFU.cjs.map → chunk-U5ZE22FV.cjs.map} +1 -1
  36. package/dist/{chunk-5UZZ5UTH.js → chunk-UL7QF323.js} +2 -2
  37. package/dist/{chunk-XBL4OPPW.js → chunk-V6FISTDB.js} +2 -2
  38. package/dist/{chunk-5JMFC6DQ.js → chunk-VGK6CXYG.js} +5 -5
  39. package/dist/{chunk-MAWBYVGA.cjs → chunk-VSUGMXAV.cjs} +87 -87
  40. package/dist/{chunk-MAWBYVGA.cjs.map → chunk-VSUGMXAV.cjs.map} +1 -1
  41. package/dist/{chunk-5MJBM4AT.js → chunk-VXMKRJYN.js} +46 -2
  42. package/dist/{chunk-5MJBM4AT.js.map → chunk-VXMKRJYN.js.map} +1 -1
  43. package/dist/{chunk-YUYDBVBF.js → chunk-YXF4JKKQ.js} +4 -4
  44. package/dist/components/case-studies/index.cjs +8 -8
  45. package/dist/components/case-studies/index.js +2 -2
  46. package/dist/components/chat/index.cjs +2 -2
  47. package/dist/components/chat/index.js +1 -1
  48. package/dist/components/contact/index.cjs +3 -3
  49. package/dist/components/contact/index.js +2 -2
  50. package/dist/components/docs/index.cjs +5 -5
  51. package/dist/components/docs/index.js +4 -4
  52. package/dist/components/embeds/index.cjs +3 -3
  53. package/dist/components/embeds/index.js +2 -2
  54. package/dist/components/faq/index.cjs +3 -3
  55. package/dist/components/faq/index.js +2 -2
  56. package/dist/components/features/index.cjs +2 -2
  57. package/dist/components/features/index.js +1 -1
  58. package/dist/components/help-center-pages/index.cjs +22 -22
  59. package/dist/components/help-center-pages/index.js +13 -13
  60. package/dist/components/index.cjs +136 -132
  61. package/dist/components/index.cjs.map +1 -1
  62. package/dist/components/index.js +15 -11
  63. package/dist/components/index.js.map +1 -1
  64. package/dist/components/meeting-scheduler/index.cjs +34 -34
  65. package/dist/components/meeting-scheduler/index.js +3 -3
  66. package/dist/components/navigation/index.cjs +2 -2
  67. package/dist/components/navigation/index.js +1 -1
  68. package/dist/components/onboarding-guides/index.cjs +5 -5
  69. package/dist/components/onboarding-guides/index.js +4 -4
  70. package/dist/components/related-content/index.cjs +3 -3
  71. package/dist/components/related-content/index.js +2 -2
  72. package/dist/components/tickets/index.cjs +6 -6
  73. package/dist/components/tickets/index.js +5 -5
  74. package/dist/components/ui/index.cjs +6 -2
  75. package/dist/components/ui/index.cjs.map +1 -1
  76. package/dist/components/ui/index.js +5 -1
  77. package/dist/components/ui/test-run.d.ts +13 -0
  78. package/dist/components/ui/test-run.d.ts.map +1 -1
  79. package/dist/index.cjs +6 -2
  80. package/dist/index.cjs.map +1 -1
  81. package/dist/index.js +5 -1
  82. package/package.json +1 -1
  83. package/src/components/ui/test-run.tsx +59 -6
  84. package/src/stories/TestRun.stories.tsx +20 -2
  85. package/dist/chunk-BVBY7UMD.cjs.map +0 -1
  86. /package/dist/{chunk-SIMZ3VS2.js.map → chunk-45TSVW73.js.map} +0 -0
  87. /package/dist/{chunk-ARTBN7XU.js.map → chunk-A5WEANTA.js.map} +0 -0
  88. /package/dist/{chunk-KXB6PGWV.js.map → chunk-CJ55TI4A.js.map} +0 -0
  89. /package/dist/{chunk-FLI5RMO4.js.map → chunk-GXSKS5RO.js.map} +0 -0
  90. /package/dist/{chunk-W5TUW7US.js.map → chunk-I75L6RSN.js.map} +0 -0
  91. /package/dist/{chunk-SIFO7F7J.js.map → chunk-J6TFTLXF.js.map} +0 -0
  92. /package/dist/{chunk-4XFAIQMV.js.map → chunk-O3CJ6IWP.js.map} +0 -0
  93. /package/dist/{chunk-6IQKCE6Q.js.map → chunk-OCNHD5XM.js.map} +0 -0
  94. /package/dist/{chunk-YR3YLAGA.js.map → chunk-QRAGH5CS.js.map} +0 -0
  95. /package/dist/{chunk-5UZZ5UTH.js.map → chunk-UL7QF323.js.map} +0 -0
  96. /package/dist/{chunk-XBL4OPPW.js.map → chunk-V6FISTDB.js.map} +0 -0
  97. /package/dist/{chunk-5JMFC6DQ.js.map → chunk-VGK6CXYG.js.map} +0 -0
  98. /package/dist/{chunk-YUYDBVBF.js.map → chunk-YXF4JKKQ.js.map} +0 -0
@@ -2,7 +2,8 @@
2
2
 
3
3
  import type { ColumnDef, Row } from '@tanstack/react-table'
4
4
  import * as React from 'react'
5
- import { SearchIcon } from '../icons-v2-generated'
5
+ import { Copy02Icon, SearchIcon } from '../icons-v2-generated'
6
+ import { useCopyToClipboard } from '../../hooks/use-copy-to-clipboard'
6
7
  import { cn } from '../../utils/cn'
7
8
  import { formatTime } from '../../utils/format-date'
8
9
  import { DataTable } from './data-table'
@@ -10,6 +11,7 @@ import { useDataTable } from './data-table/use-data-table'
10
11
  import { NoData } from './no-data'
11
12
  import type { QueryResultRow } from './query-report-table'
12
13
  import { ScrollShadow } from './scroll-fade'
14
+ import { Tag } from './tag'
13
15
 
14
16
  /*
15
17
  * Live test-run building blocks: the UI (timing stats, one-row skeleton,
@@ -129,15 +131,37 @@ export interface TestRunResultsProps {
129
131
  className?: string
130
132
  }
131
133
 
134
+ /** Red error banner with a copy-to-clipboard action, per the test-run design. */
135
+ export function TestRunErrorBanner({ error, className }: { error: string; className?: string }) {
136
+ const { copy } = useCopyToClipboard({ successDescription: 'Error message copied to clipboard' })
137
+ return (
138
+ <div
139
+ role="alert"
140
+ className={cn(
141
+ 'flex items-center justify-between gap-[var(--spacing-system-s)]',
142
+ 'rounded-[6px] border border-ods-error bg-ods-error-secondary',
143
+ 'px-[var(--spacing-system-mf)] py-[var(--spacing-system-s)]',
144
+ className,
145
+ )}
146
+ >
147
+ <p className="text-h4 text-ods-error min-w-0 break-words">{error}</p>
148
+ <button
149
+ type="button"
150
+ aria-label="Copy error message"
151
+ onClick={() => copy(error)}
152
+ className="shrink-0 text-ods-error hover:opacity-80 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-focus rounded-sm"
153
+ >
154
+ <Copy02Icon className="size-5" />
155
+ </button>
156
+ </div>
157
+ )
158
+ }
159
+
132
160
  /** Error line + empty state + result table for a finished/running test run. */
133
161
  export function TestRunResults({ isActive, displayRows, firstError, className }: TestRunResultsProps) {
134
162
  return (
135
163
  <div className={cn('flex flex-col gap-[var(--spacing-system-xsf)]', className)}>
136
- {firstError && (
137
- <p role="alert" className="text-h6 text-ods-error">
138
- {firstError}
139
- </p>
140
- )}
164
+ {firstError && <TestRunErrorBanner error={firstError} />}
141
165
  {!isActive && displayRows.length === 0 ? (
142
166
  // With zero rows the error line alone explains the outcome; a
143
167
  // "No results returned" empty state next to it would mislead.
@@ -164,6 +188,30 @@ export function TimingStat({ value, label, className }: { value: string; label:
164
188
  )
165
189
  }
166
190
 
191
+ /** Overall run outcome shown in a test-run controls row. */
192
+ export type TestRunStatus = 'idle' | 'running' | 'success' | 'error'
193
+
194
+ const TEST_RUN_STATUS_TAGS: Record<Exclude<TestRunStatus, 'idle'>, { label: string; variant: 'warning' | 'success' | 'error' }> = {
195
+ running: { label: 'IN PROCESS', variant: 'warning' },
196
+ success: { label: 'SUCCESS', variant: 'success' },
197
+ error: { label: 'ERROR', variant: 'error' },
198
+ }
199
+
200
+ /** Status stat cell: "-" before the first run, then a colored state tag. */
201
+ export function TestRunStatusStat({ status, className }: { status: TestRunStatus; className?: string }) {
202
+ const tag = status === 'idle' ? null : TEST_RUN_STATUS_TAGS[status]
203
+ return (
204
+ <div className={cn('flex flex-col justify-center items-start min-w-0 gap-[var(--spacing-system-xxs)]', className)}>
205
+ {tag ? (
206
+ <Tag label={tag.label} variant={tag.variant} className="pointer-events-none" />
207
+ ) : (
208
+ <span className="text-h4 text-ods-text-secondary truncate">-</span>
209
+ )}
210
+ <span className="text-h6 text-ods-text-secondary truncate">Status</span>
211
+ </div>
212
+ )
213
+ }
214
+
167
215
  /**
168
216
  * The transport-side contract `useTestRunState` observes. Matches the shape
169
217
  * of a live-campaign hook (e.g. Fleet live queries in OpenFrame) without
@@ -248,6 +296,10 @@ export function useTestRunState(campaign: TestRunCampaignState) {
248
296
 
249
297
  const firstError = isFinished && campaign.errors.length > 0 ? campaign.errors[0].error : null
250
298
 
299
+ // Overall run outcome for the Status stat: '-' until a run starts, then
300
+ // IN PROCESS while active, and SUCCESS/ERROR once the campaign finishes.
301
+ const status: TestRunStatus = isActive ? 'running' : hasRun && isFinished ? (firstError ? 'error' : 'success') : 'idle'
302
+
251
303
  // Started/Duration show zeros until the current run's timing is real:
252
304
  // hasRun=false after a reset, and campaignStatus resets while the next
253
305
  // run is being created, so stale values never linger on screen.
@@ -271,6 +323,7 @@ export function useTestRunState(campaign: TestRunCampaignState) {
271
323
  isActive,
272
324
  isFinished,
273
325
  showResults,
326
+ status,
274
327
  firstError,
275
328
  startedLabel,
276
329
  durationLabel,
@@ -1,5 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
- import { TestResultsSkeleton, TestRunResults, TimingStat } from '../components/ui/test-run';
2
+ import { TestResultsSkeleton, TestRunResults, TestRunStatusStat, TimingStat } from '../components/ui/test-run';
3
3
 
4
4
  const meta = {
5
5
  title: 'UI/TestRun',
@@ -85,7 +85,7 @@ export const EmptyResult: Story = {
85
85
  ),
86
86
  };
87
87
 
88
- /** Finished with an error: the alert line replaces the empty state. */
88
+ /** Finished with an error: red banner with a copy action replaces the empty state. */
89
89
  export const WithError: Story = {
90
90
  args: {
91
91
  isActive: false,
@@ -111,8 +111,26 @@ export const TimingAndSkeleton: Story = {
111
111
  <div className="flex items-center gap-[var(--spacing-system-m)]">
112
112
  <TimingStat value="02:15 PM" label="Started" className="flex-1" />
113
113
  <TimingStat value="00:00:05" label="Duration" className="flex-1" />
114
+ <TestRunStatusStat status="running" className="flex-1" />
114
115
  </div>
115
116
  <TestResultsSkeleton />
116
117
  </div>
117
118
  ),
118
119
  };
120
+
121
+ /** The four Status stat states: "-" before a run, then a colored tag. */
122
+ export const StatusStates: Story = {
123
+ args: {
124
+ isActive: false,
125
+ displayRows: [],
126
+ firstError: null,
127
+ },
128
+ render: () => (
129
+ <div className="flex max-w-[720px] items-center gap-[var(--spacing-system-l)] bg-ods-bg p-[var(--spacing-system-mf)]">
130
+ <TestRunStatusStat status="idle" />
131
+ <TestRunStatusStat status="running" />
132
+ <TestRunStatusStat status="success" />
133
+ <TestRunStatusStat status="error" />
134
+ </div>
135
+ ),
136
+ };