@workflow/web-shared 5.0.0-beta.1 → 5.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/components/error-boundary.js +1 -1
- package/dist/components/event-list-view.d.ts +18 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +219 -125
- package/dist/components/hook-actions.js +1 -1
- package/dist/components/index.d.ts +5 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +6 -2
- package/dist/components/new-trace-viewer/components/copy-button.d.ts +9 -0
- package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/copy-button.js +27 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +10 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.js +44 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts +18 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +54 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +25 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +101 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +15 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/split-pane.js +105 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +221 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +19 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/use-row-window.js +69 -0
- package/dist/components/new-trace-viewer/context.d.ts +15 -0
- package/dist/components/new-trace-viewer/context.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/context.js +47 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts +10 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/detail-panel.js +13 -0
- package/dist/components/new-trace-viewer/icons.d.ts +6 -0
- package/dist/components/new-trace-viewer/icons.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/icons.js +15 -0
- package/dist/components/new-trace-viewer/search.d.ts +19 -0
- package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/search.js +134 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts +11 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.js +400 -0
- package/dist/components/new-trace-viewer/types.d.ts +1 -0
- package/dist/components/new-trace-viewer/types.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/types.js +2 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts +1 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/util/constants.js +2 -0
- package/dist/components/new-trace-viewer/utils.d.ts +46 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +330 -0
- package/dist/components/run-trace-view.d.ts +2 -1
- package/dist/components/run-trace-view.d.ts.map +1 -1
- package/dist/components/run-trace-view.js +3 -3
- package/dist/components/sidebar/attribute-panel.d.ts +7 -1
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +131 -70
- package/dist/components/sidebar/conversation-view.js +1 -1
- package/dist/components/sidebar/copyable-data-block.d.ts +1 -0
- package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +16 -15
- package/dist/components/sidebar/detail-card.d.ts +5 -6
- package/dist/components/sidebar/detail-card.d.ts.map +1 -1
- package/dist/components/sidebar/detail-card.js +32 -16
- package/dist/components/sidebar/entity-detail-panel.d.ts +3 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +20 -37
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +21 -15
- package/dist/components/sidebar/resolve-hook-modal.js +1 -1
- package/dist/components/sidebar/sidebar-data-context.d.ts +29 -0
- package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar-data-context.js +19 -0
- package/dist/components/stream-viewer.d.ts +1 -1
- package/dist/components/stream-viewer.d.ts.map +1 -1
- package/dist/components/stream-viewer.js +3 -27
- package/dist/components/trace-viewer/components/map.js +1 -1
- package/dist/components/trace-viewer/components/markers.js +1 -1
- package/dist/components/trace-viewer/components/node.js +1 -1
- package/dist/components/trace-viewer/components/search-input.js +1 -1
- package/dist/components/trace-viewer/components/search.js +1 -1
- package/dist/components/trace-viewer/components/span-content.js +1 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
- package/dist/components/trace-viewer/components/span-segments.js +1 -1
- package/dist/components/trace-viewer/components/span-strategies.js +1 -1
- package/dist/components/trace-viewer/components/ui.js +1 -1
- package/dist/components/trace-viewer/components/zoom-button.js +1 -1
- package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
- package/dist/components/trace-viewer/context.js +1 -1
- package/dist/components/trace-viewer/index.js +1 -1
- package/dist/components/trace-viewer/trace-viewer.js +1 -1
- package/dist/components/trace-viewer/types.js +1 -1
- package/dist/components/trace-viewer/util/constants.js +1 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
- package/dist/components/trace-viewer/util/timing.js +6 -9
- package/dist/components/trace-viewer/util/tree.js +1 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
- package/dist/components/trace-viewer/worker.js +1 -1
- package/dist/components/trace-viewer-new.d.ts +14 -0
- package/dist/components/trace-viewer-new.d.ts.map +1 -0
- package/dist/components/trace-viewer-new.js +22 -0
- package/dist/components/ui/alert.js +1 -1
- package/dist/components/ui/button.d.ts +10 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +46 -0
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/data-inspector.d.ts +39 -1
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +207 -22
- package/dist/components/ui/decrypt-button.js +1 -1
- package/dist/components/ui/error-card.js +1 -1
- package/dist/components/ui/error-stack-block.d.ts.map +1 -1
- package/dist/components/ui/error-stack-block.js +27 -19
- package/dist/components/ui/icon-button.d.ts +19 -0
- package/dist/components/ui/icon-button.d.ts.map +1 -0
- package/dist/components/ui/icon-button.js +29 -0
- package/dist/components/ui/inspector-theme.d.ts +9 -10
- package/dist/components/ui/inspector-theme.d.ts.map +1 -1
- package/dist/components/ui/inspector-theme.js +39 -72
- package/dist/components/ui/kbd.d.ts +6 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/kbd.js +6 -0
- package/dist/components/ui/load-more-button.js +1 -1
- package/dist/components/ui/menu-dropdown.js +1 -1
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/spinner.js +1 -1
- package/dist/components/ui/timestamp-tooltip.js +1 -1
- package/dist/components/ui/tooltip.d.ts +10 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +12 -0
- package/dist/components/workflow-trace-view.d.ts +3 -1
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +10 -5
- package/dist/components/workflow-traces/event-colors.js +1 -1
- package/dist/components/workflow-traces/trace-colors.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.d.ts +2 -2
- package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +19 -6
- package/dist/components/workflow-traces/trace-time-utils.js +1 -1
- package/dist/hooks/use-dark-mode.js +1 -1
- package/dist/hooks/use-intersection-observer.d.ts +17 -0
- package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
- package/dist/hooks/use-intersection-observer.js +29 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
- package/dist/hooks/use-load-more-on-scroll.js +28 -0
- package/dist/hooks/use-reduced-motion.d.ts +10 -0
- package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
- package/dist/hooks/use-reduced-motion.js +29 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lib/event-analysis.js +1 -1
- package/dist/lib/event-materialization.js +1 -1
- package/dist/lib/exact-event-search-id.d.ts +25 -0
- package/dist/lib/exact-event-search-id.d.ts.map +1 -0
- package/dist/lib/exact-event-search-id.js +39 -0
- package/dist/lib/hydration.d.ts +14 -1
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +157 -4
- package/dist/lib/stream-display.d.ts +18 -0
- package/dist/lib/stream-display.d.ts.map +1 -0
- package/dist/lib/stream-display.js +30 -0
- package/dist/lib/toast.js +1 -1
- package/dist/lib/trace-builder.d.ts.map +1 -1
- package/dist/lib/trace-builder.js +3 -2
- package/dist/lib/utils.d.ts +9 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +27 -32
- package/dist/styles.css +475 -1
- package/package.json +6 -4
- package/src/components/event-list-view.tsx +421 -262
- package/src/components/index.ts +13 -1
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +135 -0
- package/src/components/new-trace-viewer/components/middle-truncate/copy-selection.ts +114 -0
- package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +157 -0
- package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +132 -0
- package/src/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.ts +167 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +198 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +560 -0
- package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +94 -0
- package/src/components/new-trace-viewer/components/use-row-window.ts +93 -0
- package/src/components/new-trace-viewer/context.tsx +90 -0
- package/src/components/new-trace-viewer/detail-panel.tsx +55 -0
- package/src/components/new-trace-viewer/icons.tsx +79 -0
- package/src/components/new-trace-viewer/search.ts +178 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +762 -0
- package/src/components/new-trace-viewer/types.ts +0 -0
- package/src/components/new-trace-viewer/util/constants.ts +0 -0
- package/src/components/new-trace-viewer/utils.ts +482 -0
- package/src/components/run-trace-view.tsx +3 -0
- package/src/components/sidebar/attribute-panel.tsx +240 -196
- package/src/components/sidebar/copyable-data-block.tsx +49 -27
- package/src/components/sidebar/detail-card.tsx +119 -59
- package/src/components/sidebar/entity-detail-panel.tsx +92 -148
- package/src/components/sidebar/events-list.tsx +51 -76
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer/util/timing.ts +5 -9
- package/src/components/trace-viewer-new.tsx +57 -0
- package/src/components/ui/button.tsx +68 -0
- package/src/components/ui/data-inspector.tsx +427 -31
- package/src/components/ui/error-stack-block.tsx +39 -30
- package/src/components/ui/icon-button.tsx +53 -0
- package/src/components/ui/inspector-theme.ts +39 -81
- package/src/components/ui/kbd.tsx +21 -0
- package/src/components/ui/tooltip.tsx +47 -0
- package/src/components/workflow-trace-view.tsx +12 -2
- package/src/components/workflow-traces/trace-span-construction.ts +24 -6
- package/src/hooks/use-intersection-observer.ts +57 -0
- package/src/hooks/use-load-more-on-scroll.ts +49 -0
- package/src/hooks/use-reduced-motion.ts +34 -0
- package/src/index.ts +9 -0
- package/src/lib/exact-event-search-id.ts +67 -0
- package/src/lib/hydration.ts +169 -1
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/trace-builder.ts +2 -1
- package/src/lib/utils.ts +27 -32
- package/src/styles.css +475 -1
- package/dist/components/error-boundary.js.map +0 -1
- package/dist/components/event-list-view.js.map +0 -1
- package/dist/components/hook-actions.js.map +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/components/run-trace-view.js.map +0 -1
- package/dist/components/sidebar/attribute-panel.js.map +0 -1
- package/dist/components/sidebar/conversation-view.js.map +0 -1
- package/dist/components/sidebar/copyable-data-block.js.map +0 -1
- package/dist/components/sidebar/detail-card.js.map +0 -1
- package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
- package/dist/components/sidebar/events-list.js.map +0 -1
- package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
- package/dist/components/stream-viewer.js.map +0 -1
- package/dist/components/trace-viewer/components/map.js.map +0 -1
- package/dist/components/trace-viewer/components/markers.js.map +0 -1
- package/dist/components/trace-viewer/components/node.js.map +0 -1
- package/dist/components/trace-viewer/components/search-input.js.map +0 -1
- package/dist/components/trace-viewer/components/search.js.map +0 -1
- package/dist/components/trace-viewer/components/span-content.js.map +0 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
- package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
- package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
- package/dist/components/trace-viewer/components/ui.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
- package/dist/components/trace-viewer/context.js.map +0 -1
- package/dist/components/trace-viewer/index.js.map +0 -1
- package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
- package/dist/components/trace-viewer/types.js.map +0 -1
- package/dist/components/trace-viewer/util/constants.js.map +0 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
- package/dist/components/trace-viewer/util/timing.js.map +0 -1
- package/dist/components/trace-viewer/util/tree.js.map +0 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
- package/dist/components/trace-viewer/worker.js.map +0 -1
- package/dist/components/ui/alert.js.map +0 -1
- package/dist/components/ui/card.js.map +0 -1
- package/dist/components/ui/data-inspector.js.map +0 -1
- package/dist/components/ui/decrypt-button.js.map +0 -1
- package/dist/components/ui/error-card.js.map +0 -1
- package/dist/components/ui/error-stack-block.js.map +0 -1
- package/dist/components/ui/inspector-theme.js.map +0 -1
- package/dist/components/ui/load-more-button.js.map +0 -1
- package/dist/components/ui/menu-dropdown.js.map +0 -1
- package/dist/components/ui/skeleton.js.map +0 -1
- package/dist/components/ui/spinner.js.map +0 -1
- package/dist/components/ui/timestamp-tooltip.js.map +0 -1
- package/dist/components/workflow-trace-view.js.map +0 -1
- package/dist/components/workflow-traces/event-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
- package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
- package/dist/hooks/use-dark-mode.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/event-analysis.js.map +0 -1
- package/dist/lib/event-materialization.js.map +0 -1
- package/dist/lib/hydration.js.map +0 -1
- package/dist/lib/toast.js.map +0 -1
- package/dist/lib/trace-builder.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
const iconButtonVariants = cva(
|
|
6
|
+
[
|
|
7
|
+
'm-0 inline-flex shrink-0 appearance-none items-center justify-center border-0 bg-transparent p-0 align-baseline font-inherit no-underline [background:none] [-webkit-appearance:none] [-webkit-tap-highlight-color:transparent]',
|
|
8
|
+
'transition-colors duration-150 ease-in-out',
|
|
9
|
+
'enabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-40',
|
|
10
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--ds-focus-color)] focus-visible:outline-offset-2',
|
|
11
|
+
],
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
tertiary:
|
|
16
|
+
'text-gray-900 enabled:hover:bg-gray-alpha-200 enabled:hover:text-gray-1000 enabled:active:bg-gray-alpha-200 focus-visible:text-gray-1000',
|
|
17
|
+
muted:
|
|
18
|
+
'text-gray-900 enabled:hover:bg-gray-alpha-200 enabled:hover:text-gray-1000 enabled:active:bg-gray-alpha-200 focus-visible:text-gray-1000',
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
tiny: 'h-6 w-6 rounded-[4px] [&_svg]:h-4 [&_svg]:w-4',
|
|
22
|
+
small: 'h-8 w-8 rounded-md [&_svg]:h-4 [&_svg]:w-4',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: 'tertiary',
|
|
27
|
+
size: 'tiny',
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export type IconButtonProps = Omit<
|
|
33
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
34
|
+
'type'
|
|
35
|
+
> &
|
|
36
|
+
VariantProps<typeof iconButtonVariants> & {
|
|
37
|
+
'aria-label': string;
|
|
38
|
+
type?: 'button' | 'submit' | 'reset';
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
42
|
+
({ className, variant, size, type = 'button', ...props }, ref) => (
|
|
43
|
+
<button
|
|
44
|
+
ref={ref}
|
|
45
|
+
type={type}
|
|
46
|
+
className={cn(iconButtonVariants({ variant, size, className }))}
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
IconButton.displayName = 'IconButton';
|
|
52
|
+
|
|
53
|
+
export { iconButtonVariants };
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared theme configuration for react-inspector's ObjectInspector.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* - null:
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* - functions (special): cyan
|
|
12
|
-
* - date: magenta
|
|
4
|
+
* Colors follow Geist's Shiki JSON palette so the inspector reads the same
|
|
5
|
+
* as highlighted code blocks across the product:
|
|
6
|
+
* - property names / punctuation: --ds-gray-1000 (default foreground)
|
|
7
|
+
* - strings / numbers / booleans: --ds-green-900
|
|
8
|
+
* - null / undefined: --ds-gray-900 (muted)
|
|
9
|
+
* - regexp / function: --ds-purple-900
|
|
10
|
+
* - date: --ds-pink-900
|
|
13
11
|
*
|
|
14
|
-
*
|
|
12
|
+
* Because the `--ds-*` tokens adapt to theme automatically, the light and
|
|
13
|
+
* dark objects are intentionally identical.
|
|
15
14
|
*/
|
|
16
15
|
|
|
17
16
|
// ---------------------------------------------------------------------------
|
|
@@ -25,11 +24,11 @@ export interface InspectorThemeExtended {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
export const inspectorThemeExtendedLight: InspectorThemeExtended = {
|
|
28
|
-
OBJECT_VALUE_DATE_COLOR: '
|
|
27
|
+
OBJECT_VALUE_DATE_COLOR: 'var(--ds-pink-900)',
|
|
29
28
|
};
|
|
30
29
|
|
|
31
30
|
export const inspectorThemeExtendedDark: InspectorThemeExtended = {
|
|
32
|
-
OBJECT_VALUE_DATE_COLOR: '
|
|
31
|
+
OBJECT_VALUE_DATE_COLOR: 'var(--ds-pink-900)',
|
|
33
32
|
};
|
|
34
33
|
|
|
35
34
|
// ---------------------------------------------------------------------------
|
|
@@ -57,96 +56,55 @@ const shared = {
|
|
|
57
56
|
// Light theme
|
|
58
57
|
// ---------------------------------------------------------------------------
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
const geistTheme = {
|
|
61
60
|
...shared,
|
|
62
61
|
|
|
63
62
|
// Base text
|
|
64
63
|
BASE_COLOR: 'var(--ds-gray-1000)',
|
|
65
64
|
|
|
66
|
-
// Property names —
|
|
67
|
-
OBJECT_NAME_COLOR: 'var(--ds-gray-
|
|
65
|
+
// Property names — default foreground (matches JSON key color in Geist Shiki)
|
|
66
|
+
OBJECT_NAME_COLOR: 'var(--ds-gray-1000)',
|
|
68
67
|
|
|
69
|
-
// Strings & symbols — green
|
|
70
|
-
OBJECT_VALUE_STRING_COLOR: '
|
|
71
|
-
OBJECT_VALUE_SYMBOL_COLOR: '
|
|
68
|
+
// Strings & symbols — green
|
|
69
|
+
OBJECT_VALUE_STRING_COLOR: 'var(--ds-green-900)',
|
|
70
|
+
OBJECT_VALUE_SYMBOL_COLOR: 'var(--ds-green-900)',
|
|
72
71
|
|
|
73
|
-
// Numbers & booleans —
|
|
74
|
-
OBJECT_VALUE_NUMBER_COLOR: '
|
|
75
|
-
OBJECT_VALUE_BOOLEAN_COLOR: '
|
|
72
|
+
// Numbers & booleans — green (Geist JSON tokens)
|
|
73
|
+
OBJECT_VALUE_NUMBER_COLOR: 'var(--ds-green-900)',
|
|
74
|
+
OBJECT_VALUE_BOOLEAN_COLOR: 'var(--ds-green-900)',
|
|
76
75
|
|
|
77
|
-
// null —
|
|
76
|
+
// null — muted foreground
|
|
78
77
|
OBJECT_VALUE_NULL_COLOR: 'var(--ds-gray-900)',
|
|
79
78
|
|
|
80
|
-
// undefined —
|
|
81
|
-
OBJECT_VALUE_UNDEFINED_COLOR: 'var(--ds-gray-
|
|
79
|
+
// undefined — muted foreground
|
|
80
|
+
OBJECT_VALUE_UNDEFINED_COLOR: 'var(--ds-gray-900)',
|
|
82
81
|
|
|
83
|
-
// RegExp —
|
|
84
|
-
OBJECT_VALUE_REGEXP_COLOR: '
|
|
82
|
+
// RegExp — purple
|
|
83
|
+
OBJECT_VALUE_REGEXP_COLOR: 'var(--ds-purple-900)',
|
|
85
84
|
|
|
86
|
-
// Functions —
|
|
87
|
-
OBJECT_VALUE_FUNCTION_PREFIX_COLOR: '
|
|
85
|
+
// Functions — purple
|
|
86
|
+
OBJECT_VALUE_FUNCTION_PREFIX_COLOR: 'var(--ds-purple-900)',
|
|
88
87
|
|
|
89
|
-
// HTML (
|
|
90
|
-
HTML_TAG_COLOR: 'var(--ds-gray-
|
|
91
|
-
HTML_TAGNAME_COLOR: '
|
|
92
|
-
HTML_ATTRIBUTE_NAME_COLOR: '
|
|
93
|
-
HTML_ATTRIBUTE_VALUE_COLOR: '
|
|
94
|
-
HTML_COMMENT_COLOR: 'var(--ds-gray-
|
|
95
|
-
HTML_DOCTYPE_COLOR: 'var(--ds-gray-
|
|
88
|
+
// HTML (rarely used here, kept consistent with the palette)
|
|
89
|
+
HTML_TAG_COLOR: 'var(--ds-gray-900)',
|
|
90
|
+
HTML_TAGNAME_COLOR: 'var(--ds-blue-900)',
|
|
91
|
+
HTML_ATTRIBUTE_NAME_COLOR: 'var(--ds-amber-900)',
|
|
92
|
+
HTML_ATTRIBUTE_VALUE_COLOR: 'var(--ds-green-900)',
|
|
93
|
+
HTML_COMMENT_COLOR: 'var(--ds-gray-700)',
|
|
94
|
+
HTML_DOCTYPE_COLOR: 'var(--ds-gray-700)',
|
|
96
95
|
|
|
97
96
|
// Structural
|
|
98
|
-
ARROW_COLOR: 'var(--ds-gray-
|
|
97
|
+
ARROW_COLOR: 'var(--ds-gray-700)',
|
|
99
98
|
TABLE_BORDER_COLOR: 'var(--ds-gray-300)',
|
|
100
99
|
TABLE_TH_BACKGROUND_COLOR: 'var(--ds-gray-100)',
|
|
101
100
|
TABLE_TH_HOVER_COLOR: 'var(--ds-gray-200)',
|
|
102
|
-
TABLE_SORT_ICON_COLOR: 'var(--ds-gray-
|
|
101
|
+
TABLE_SORT_ICON_COLOR: 'var(--ds-gray-700)',
|
|
103
102
|
};
|
|
104
103
|
|
|
104
|
+
export const inspectorThemeLight = geistTheme;
|
|
105
|
+
|
|
105
106
|
// ---------------------------------------------------------------------------
|
|
106
107
|
// Dark theme
|
|
107
108
|
// ---------------------------------------------------------------------------
|
|
108
109
|
|
|
109
|
-
export const inspectorThemeDark =
|
|
110
|
-
...shared,
|
|
111
|
-
|
|
112
|
-
// Base text
|
|
113
|
-
BASE_COLOR: 'var(--ds-gray-1000)',
|
|
114
|
-
|
|
115
|
-
// Property names — white/light foreground (Node: unstyled = white in dark terminal)
|
|
116
|
-
OBJECT_NAME_COLOR: 'var(--ds-gray-900)',
|
|
117
|
-
|
|
118
|
-
// Strings & symbols — green (Node: 'green')
|
|
119
|
-
OBJECT_VALUE_STRING_COLOR: '#4ade80', // green-400
|
|
120
|
-
OBJECT_VALUE_SYMBOL_COLOR: '#4ade80',
|
|
121
|
-
|
|
122
|
-
// Numbers & booleans — yellow (Node: 'yellow')
|
|
123
|
-
OBJECT_VALUE_NUMBER_COLOR: '#facc15', // yellow-400
|
|
124
|
-
OBJECT_VALUE_BOOLEAN_COLOR: '#facc15',
|
|
125
|
-
|
|
126
|
-
// null — bold foreground / white (Node: 'bold')
|
|
127
|
-
OBJECT_VALUE_NULL_COLOR: 'var(--ds-gray-1000)',
|
|
128
|
-
|
|
129
|
-
// undefined — grey (Node: 'grey')
|
|
130
|
-
OBJECT_VALUE_UNDEFINED_COLOR: 'var(--ds-gray-500)',
|
|
131
|
-
|
|
132
|
-
// RegExp — red (Node regexp palette)
|
|
133
|
-
OBJECT_VALUE_REGEXP_COLOR: '#f87171', // red-400
|
|
134
|
-
|
|
135
|
-
// Functions — cyan (Node: 'special' → 'cyan')
|
|
136
|
-
OBJECT_VALUE_FUNCTION_PREFIX_COLOR: '#22d3ee', // cyan-400
|
|
137
|
-
|
|
138
|
-
// HTML
|
|
139
|
-
HTML_TAG_COLOR: 'var(--ds-gray-500)',
|
|
140
|
-
HTML_TAGNAME_COLOR: '#22d3ee',
|
|
141
|
-
HTML_ATTRIBUTE_NAME_COLOR: '#facc15',
|
|
142
|
-
HTML_ATTRIBUTE_VALUE_COLOR: '#4ade80',
|
|
143
|
-
HTML_COMMENT_COLOR: 'var(--ds-gray-500)',
|
|
144
|
-
HTML_DOCTYPE_COLOR: 'var(--ds-gray-500)',
|
|
145
|
-
|
|
146
|
-
// Structural
|
|
147
|
-
ARROW_COLOR: 'var(--ds-gray-500)',
|
|
148
|
-
TABLE_BORDER_COLOR: 'var(--ds-gray-300)',
|
|
149
|
-
TABLE_TH_BACKGROUND_COLOR: 'var(--ds-gray-100)',
|
|
150
|
-
TABLE_TH_HOVER_COLOR: 'var(--ds-gray-200)',
|
|
151
|
-
TABLE_SORT_ICON_COLOR: 'var(--ds-gray-500)',
|
|
152
|
-
};
|
|
110
|
+
export const inspectorThemeDark = geistTheme;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { cn } from '../../lib/utils';
|
|
3
|
+
|
|
4
|
+
export function Kbd({
|
|
5
|
+
children,
|
|
6
|
+
className,
|
|
7
|
+
}: {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
}): ReactNode {
|
|
11
|
+
return (
|
|
12
|
+
<kbd
|
|
13
|
+
className={cn(
|
|
14
|
+
'inline-flex h-5 min-w-5 items-center justify-center rounded bg-background-100/20 px-1 text-center font-sans text-xs leading-none',
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
{children}
|
|
19
|
+
</kbd>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
|
|
7
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
8
|
+
|
|
9
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
10
|
+
|
|
11
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
12
|
+
|
|
13
|
+
const TooltipContent = React.forwardRef<
|
|
14
|
+
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
15
|
+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {
|
|
16
|
+
showArrow?: boolean;
|
|
17
|
+
}
|
|
18
|
+
>(
|
|
19
|
+
(
|
|
20
|
+
{ className, sideOffset = 8, showArrow = true, children, ...props },
|
|
21
|
+
ref
|
|
22
|
+
) => (
|
|
23
|
+
<TooltipPrimitive.Portal>
|
|
24
|
+
<TooltipPrimitive.Content
|
|
25
|
+
ref={ref}
|
|
26
|
+
sideOffset={sideOffset}
|
|
27
|
+
className={cn(
|
|
28
|
+
'z-[99999] flex items-center gap-1 rounded-[10px] bg-gray-1000 px-2 py-1.5 !text-label-13 text-background-100 shadow-md select-none',
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
>
|
|
33
|
+
{children}
|
|
34
|
+
{showArrow ? (
|
|
35
|
+
<TooltipPrimitive.Arrow
|
|
36
|
+
width={11}
|
|
37
|
+
height={5}
|
|
38
|
+
className="fill-gray-1000"
|
|
39
|
+
/>
|
|
40
|
+
) : null}
|
|
41
|
+
</TooltipPrimitive.Content>
|
|
42
|
+
</TooltipPrimitive.Portal>
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
46
|
+
|
|
47
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
@@ -17,6 +17,7 @@ import type { MouseEvent as ReactMouseEvent, ReactNode } from 'react';
|
|
|
17
17
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
18
18
|
import { createPortal } from 'react-dom';
|
|
19
19
|
import { useToast } from '../lib/toast';
|
|
20
|
+
import { buildTrace, type TraceWithMeta } from '../lib/trace-builder';
|
|
20
21
|
import { ErrorBoundary } from './error-boundary';
|
|
21
22
|
import {
|
|
22
23
|
EntityDetailPanel,
|
|
@@ -36,7 +37,6 @@ import {
|
|
|
36
37
|
getCustomSpanClassName,
|
|
37
38
|
getCustomSpanEventClassName,
|
|
38
39
|
} from './workflow-traces/trace-colors';
|
|
39
|
-
import { buildTrace, type TraceWithMeta } from '../lib/trace-builder';
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* While a run is live, continuously grow root.duration and rescale so the
|
|
@@ -767,6 +767,7 @@ export const WorkflowTraceViewer = ({
|
|
|
767
767
|
onResolveHook,
|
|
768
768
|
onCancelRun,
|
|
769
769
|
onStreamClick,
|
|
770
|
+
onRunClick,
|
|
770
771
|
onSpanSelect,
|
|
771
772
|
onLoadEventData,
|
|
772
773
|
onLoadMoreSpans,
|
|
@@ -796,6 +797,8 @@ export const WorkflowTraceViewer = ({
|
|
|
796
797
|
onCancelRun?: (runId: string) => Promise<void>;
|
|
797
798
|
/** Callback when a stream reference is clicked in the detail panel */
|
|
798
799
|
onStreamClick?: (streamId: string) => void;
|
|
800
|
+
/** Callback when a run reference is clicked in the detail panel */
|
|
801
|
+
onRunClick?: (runId: string) => void;
|
|
799
802
|
/** Callback when a span is selected. */
|
|
800
803
|
onSpanSelect?: (info: SpanSelectionInfo) => void;
|
|
801
804
|
/** Callback to load event data for a specific event (lazy loading in sidebar) */
|
|
@@ -903,6 +906,12 @@ export const WorkflowTraceViewer = ({
|
|
|
903
906
|
});
|
|
904
907
|
}, [events, selectedSpan?.spanId]);
|
|
905
908
|
|
|
909
|
+
// Reset selected span when navigating to a different run
|
|
910
|
+
useEffect(() => {
|
|
911
|
+
setSelectedSpan(null);
|
|
912
|
+
setDeselectTrigger((n) => n + 1);
|
|
913
|
+
}, [run?.runId]);
|
|
914
|
+
|
|
906
915
|
const handleClose = useCallback(() => {
|
|
907
916
|
setSelectedSpan(null);
|
|
908
917
|
setDeselectTrigger((n) => n + 1);
|
|
@@ -965,7 +974,7 @@ export const WorkflowTraceViewer = ({
|
|
|
965
974
|
}
|
|
966
975
|
|
|
967
976
|
return (
|
|
968
|
-
<div className="relative w-full h-full flex">
|
|
977
|
+
<div className="relative w-full h-full flex flex-row">
|
|
969
978
|
{/* Timeline (takes remaining space) */}
|
|
970
979
|
<div className="flex-1 min-w-0 relative">
|
|
971
980
|
<TraceViewerContextProvider
|
|
@@ -1140,6 +1149,7 @@ export const WorkflowTraceViewer = ({
|
|
|
1140
1149
|
<EntityDetailPanel
|
|
1141
1150
|
run={run}
|
|
1142
1151
|
onStreamClick={onStreamClick}
|
|
1152
|
+
onRunClick={onRunClick}
|
|
1143
1153
|
spanDetailData={spanDetailData ?? null}
|
|
1144
1154
|
spanDetailError={spanDetailError}
|
|
1145
1155
|
spanDetailLoading={spanDetailLoading}
|
|
@@ -59,7 +59,7 @@ export const waitEventsToWaitEntity = (
|
|
|
59
59
|
waitId: string;
|
|
60
60
|
runId: string;
|
|
61
61
|
createdAt: Date;
|
|
62
|
-
resumeAt
|
|
62
|
+
resumeAt?: Date;
|
|
63
63
|
completedAt?: Date;
|
|
64
64
|
} | null => {
|
|
65
65
|
const startEvent = events.find((event) => event.eventType === 'wait_created');
|
|
@@ -73,7 +73,9 @@ export const waitEventsToWaitEntity = (
|
|
|
73
73
|
waitId: startEvent.correlationId,
|
|
74
74
|
runId: startEvent.runId,
|
|
75
75
|
createdAt: startEvent.createdAt,
|
|
76
|
-
resumeAt: startEvent.eventData?.resumeAt
|
|
76
|
+
resumeAt: startEvent.eventData?.resumeAt
|
|
77
|
+
? new Date(startEvent.eventData.resumeAt)
|
|
78
|
+
: undefined,
|
|
77
79
|
completedAt: completedEvent?.createdAt,
|
|
78
80
|
};
|
|
79
81
|
};
|
|
@@ -81,13 +83,29 @@ export const waitEventsToWaitEntity = (
|
|
|
81
83
|
/**
|
|
82
84
|
* Converts a workflow Wait to an OpenTelemetry Span
|
|
83
85
|
*/
|
|
84
|
-
export function waitToSpan(
|
|
86
|
+
export function waitToSpan(
|
|
87
|
+
events: Event[],
|
|
88
|
+
maxEndTime: Date,
|
|
89
|
+
fallbackEndTime = maxEndTime
|
|
90
|
+
): Span | null {
|
|
85
91
|
const wait = waitEventsToWaitEntity(events);
|
|
86
92
|
if (!wait) {
|
|
87
93
|
return null;
|
|
88
94
|
}
|
|
89
95
|
const startTime = wait.createdAt;
|
|
90
|
-
const
|
|
96
|
+
const startMs = startTime.getTime();
|
|
97
|
+
let endTime = wait.completedAt;
|
|
98
|
+
if (!endTime) {
|
|
99
|
+
const fallbackCap =
|
|
100
|
+
wait.resumeAt && wait.resumeAt.getTime() < fallbackEndTime.getTime()
|
|
101
|
+
? wait.resumeAt
|
|
102
|
+
: fallbackEndTime;
|
|
103
|
+
endTime =
|
|
104
|
+
maxEndTime.getTime() > startMs &&
|
|
105
|
+
maxEndTime.getTime() < fallbackCap.getTime()
|
|
106
|
+
? maxEndTime
|
|
107
|
+
: fallbackCap;
|
|
108
|
+
}
|
|
91
109
|
const start = dateToOtelTime(startTime);
|
|
92
110
|
const end = dateToOtelTime(endTime);
|
|
93
111
|
const duration = calculateDuration(startTime, endTime);
|
|
@@ -225,7 +243,7 @@ export function stepToSpan(stepEvents: Event[], maxEndTime: Date): Span | null {
|
|
|
225
243
|
|
|
226
244
|
return {
|
|
227
245
|
spanId: String(step.stepId),
|
|
228
|
-
name: parsedName?.shortName ??
|
|
246
|
+
name: parsedName?.shortName ?? String(step.stepName),
|
|
229
247
|
kind: 1, // INTERNAL span kind
|
|
230
248
|
resource,
|
|
231
249
|
library: WORKFLOW_LIBRARY,
|
|
@@ -296,7 +314,7 @@ export function hookToSpan(hookEvents: Event[], maxEndTime: Date): Span | null {
|
|
|
296
314
|
|
|
297
315
|
return {
|
|
298
316
|
spanId: String(hook.hookId),
|
|
299
|
-
name: String(hook.hookId),
|
|
317
|
+
name: hook.token ?? String(hook.hookId),
|
|
300
318
|
kind: 1, // INTERNAL span kind
|
|
301
319
|
resource: 'hook',
|
|
302
320
|
library: WORKFLOW_LIBRARY,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { RefObject } from 'react';
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
interface UseIntersectionObserverArgs
|
|
7
|
+
extends Omit<IntersectionObserverInit, 'root'> {
|
|
8
|
+
/**
|
|
9
|
+
* Scroll container the target is observed within. Defaults to the viewport.
|
|
10
|
+
* Passed as a ref so it resolves after commit (when the node exists).
|
|
11
|
+
*/
|
|
12
|
+
rootRef?: RefObject<Element | null>;
|
|
13
|
+
freezeOnceVisible?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the latest IntersectionObserverEntry for `elementRef`.
|
|
18
|
+
* Ported from vercel/front's `@vercel/hooks` `useIntersectionObserver`, with
|
|
19
|
+
* `root` threaded as a ref so we can observe inside a custom scroll container.
|
|
20
|
+
*/
|
|
21
|
+
export function useIntersectionObserver(
|
|
22
|
+
elementRef: RefObject<Element | null>,
|
|
23
|
+
{
|
|
24
|
+
threshold = 0,
|
|
25
|
+
rootRef,
|
|
26
|
+
rootMargin = '0%',
|
|
27
|
+
freezeOnceVisible = false,
|
|
28
|
+
}: UseIntersectionObserverArgs = {}
|
|
29
|
+
): IntersectionObserverEntry | undefined {
|
|
30
|
+
const [entry, setEntry] = useState<IntersectionObserverEntry>();
|
|
31
|
+
|
|
32
|
+
const frozen = entry?.isIntersecting && freezeOnceVisible;
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const node = elementRef?.current;
|
|
36
|
+
|
|
37
|
+
const hasIOSupport = !!window.IntersectionObserver;
|
|
38
|
+
|
|
39
|
+
if (!hasIOSupport || frozen || !node) return;
|
|
40
|
+
|
|
41
|
+
const updateEntry = ([entry]: IntersectionObserverEntry[]): void => {
|
|
42
|
+
setEntry(entry);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const observer = new IntersectionObserver(updateEntry, {
|
|
46
|
+
threshold,
|
|
47
|
+
root: rootRef?.current ?? null,
|
|
48
|
+
rootMargin,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
observer.observe(node);
|
|
52
|
+
|
|
53
|
+
return () => observer.disconnect();
|
|
54
|
+
}, [elementRef, threshold, rootRef, rootMargin, frozen]);
|
|
55
|
+
|
|
56
|
+
return entry;
|
|
57
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { RefObject } from 'react';
|
|
4
|
+
import { useEffect, useRef } from 'react';
|
|
5
|
+
import { useIntersectionObserver } from './use-intersection-observer';
|
|
6
|
+
|
|
7
|
+
interface UseLoadMoreOnScrollOptions {
|
|
8
|
+
hasMore: boolean;
|
|
9
|
+
isLoadingMore: boolean;
|
|
10
|
+
/** Scroll container the sentinel lives in. Defaults to the viewport. */
|
|
11
|
+
rootRef?: RefObject<Element | null>;
|
|
12
|
+
rootMargin?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Triggers `loadMore` when a sentinel element scrolls into view.
|
|
17
|
+
* Returns a ref to attach to an invisible sentinel `<div>` placed after the
|
|
18
|
+
* list content. Ported from vercel/front's `@vercel/hooks`
|
|
19
|
+
* `useLoadMoreOnScroll`.
|
|
20
|
+
*
|
|
21
|
+
* Because it keys off `isIntersecting`/`isLoadingMore`, it self-continues:
|
|
22
|
+
* if the sentinel is still in view once a page finishes loading, the next
|
|
23
|
+
* page is requested automatically.
|
|
24
|
+
*/
|
|
25
|
+
export function useLoadMoreOnScroll(
|
|
26
|
+
loadMore: () => void,
|
|
27
|
+
{
|
|
28
|
+
hasMore,
|
|
29
|
+
isLoadingMore,
|
|
30
|
+
rootRef,
|
|
31
|
+
rootMargin = '400px',
|
|
32
|
+
}: UseLoadMoreOnScrollOptions
|
|
33
|
+
) {
|
|
34
|
+
const sentinelRef = useRef<HTMLDivElement>(null);
|
|
35
|
+
const entry = useIntersectionObserver(sentinelRef, { rootRef, rootMargin });
|
|
36
|
+
|
|
37
|
+
const loadMoreRef = useRef(loadMore);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
loadMoreRef.current = loadMore;
|
|
40
|
+
}, [loadMore]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (entry?.isIntersecting && hasMore && !isLoadingMore) {
|
|
44
|
+
loadMoreRef.current();
|
|
45
|
+
}
|
|
46
|
+
}, [entry?.isIntersecting, hasMore, isLoadingMore]);
|
|
47
|
+
|
|
48
|
+
return sentinelRef;
|
|
49
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
const QUERY = '(prefers-reduced-motion: reduce)';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Hook that detects whether the user has requested reduced motion and reacts
|
|
9
|
+
* to changes. Mirrors the `prefers-reduced-motion: reduce` media query so
|
|
10
|
+
* components can skip or shorten animations for users with motion
|
|
11
|
+
* sensitivities (e.g. vestibular disorders).
|
|
12
|
+
*
|
|
13
|
+
* @returns `true` if the user prefers reduced motion, `false` otherwise
|
|
14
|
+
*/
|
|
15
|
+
export const useReducedMotion = (): boolean => {
|
|
16
|
+
const [reduced, setReduced] = useState(() => {
|
|
17
|
+
if (typeof window === 'undefined' || !window.matchMedia) return false;
|
|
18
|
+
return window.matchMedia(QUERY).matches;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (typeof window === 'undefined' || !window.matchMedia) return;
|
|
23
|
+
|
|
24
|
+
const media = window.matchMedia(QUERY);
|
|
25
|
+
const onChange = (): void => setReduced(media.matches);
|
|
26
|
+
|
|
27
|
+
media.addEventListener('change', onChange);
|
|
28
|
+
onChange();
|
|
29
|
+
|
|
30
|
+
return () => media.removeEventListener('change', onChange);
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
return reduced;
|
|
34
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,13 @@ export {
|
|
|
14
14
|
waitEventsToWaitEntity,
|
|
15
15
|
} from './components/workflow-traces/trace-span-construction';
|
|
16
16
|
export type { EventAnalysis } from './lib/event-analysis';
|
|
17
|
+
export {
|
|
18
|
+
parseExactWorkflowSearchId,
|
|
19
|
+
looksLikeWorkflowIdSearchInput,
|
|
20
|
+
type ExactWorkflowSearchId,
|
|
21
|
+
type ExactWorkflowSearchIdKind,
|
|
22
|
+
type ExactIdSearchResult,
|
|
23
|
+
} from './lib/exact-event-search-id';
|
|
17
24
|
export {
|
|
18
25
|
analyzeEvents,
|
|
19
26
|
hasPendingHooksFromEvents,
|
|
@@ -40,6 +47,7 @@ export {
|
|
|
40
47
|
ENCRYPTED_PLACEHOLDER,
|
|
41
48
|
extractStreamIds,
|
|
42
49
|
getWebRevivers,
|
|
50
|
+
hasEncryptedFields,
|
|
43
51
|
hydrateResourceIO,
|
|
44
52
|
hydrateResourceIOWithKey,
|
|
45
53
|
isClassInstanceRef,
|
|
@@ -49,6 +57,7 @@ export {
|
|
|
49
57
|
STREAM_REF_TYPE,
|
|
50
58
|
truncateId,
|
|
51
59
|
} from './lib/hydration';
|
|
60
|
+
export type { DecodedStreamChunkSource } from './lib/stream-display';
|
|
52
61
|
export type { ToastAdapter } from './lib/toast';
|
|
53
62
|
export { ToastProvider, useToast } from './lib/toast';
|
|
54
63
|
export type { StreamStep } from './lib/utils';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Event } from '@workflow/world';
|
|
2
|
+
|
|
3
|
+
const WORKFLOW_ULID_BODY = '[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}';
|
|
4
|
+
|
|
5
|
+
const STEP_ID_PATTERN = new RegExp(`^step_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
6
|
+
const WAIT_ID_PATTERN = new RegExp(`^wait_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
7
|
+
const HOOK_ID_PATTERN = new RegExp(`^hook_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
8
|
+
const EVENT_ID_PATTERN = new RegExp(`^evnt_(${WORKFLOW_ULID_BODY})$`, 'i');
|
|
9
|
+
|
|
10
|
+
const WORKFLOW_ID_PREFIX_PATTERN = /^(step_|wait_|hook_|evnt_|wrun_)/i;
|
|
11
|
+
|
|
12
|
+
export type ExactWorkflowSearchIdKind = 'step' | 'wait' | 'hook' | 'event';
|
|
13
|
+
|
|
14
|
+
export type ExactWorkflowSearchId = {
|
|
15
|
+
kind: ExactWorkflowSearchIdKind;
|
|
16
|
+
id: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type ExactIdSearchResult =
|
|
20
|
+
| { status: 'ok'; events: Event[]; truncated?: boolean }
|
|
21
|
+
| { status: 'not_found' }
|
|
22
|
+
| { status: 'error'; message: string };
|
|
23
|
+
|
|
24
|
+
function matchPrefixedId(
|
|
25
|
+
pattern: RegExp,
|
|
26
|
+
prefix: 'step' | 'wait' | 'hook' | 'evnt',
|
|
27
|
+
kind: ExactWorkflowSearchIdKind,
|
|
28
|
+
query: string
|
|
29
|
+
): ExactWorkflowSearchId | null {
|
|
30
|
+
const match = query.match(pattern);
|
|
31
|
+
if (!match) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return { kind, id: `${prefix}_${match[1].toUpperCase()}` };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns a parsed workflow ID when `query` is a full step, wait, hook, or event ID.
|
|
39
|
+
* Partial IDs and run IDs (`wrun_`) are ignored. ULID bodies are matched case-insensitively
|
|
40
|
+
* and normalized to uppercase in the returned ID.
|
|
41
|
+
*/
|
|
42
|
+
export function parseExactWorkflowSearchId(
|
|
43
|
+
query: string
|
|
44
|
+
): ExactWorkflowSearchId | null {
|
|
45
|
+
const trimmed = query.trim();
|
|
46
|
+
if (!trimmed) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
matchPrefixedId(STEP_ID_PATTERN, 'step', 'step', trimmed) ??
|
|
52
|
+
matchPrefixedId(WAIT_ID_PATTERN, 'wait', 'wait', trimmed) ??
|
|
53
|
+
matchPrefixedId(HOOK_ID_PATTERN, 'hook', 'hook', trimmed) ??
|
|
54
|
+
matchPrefixedId(EVENT_ID_PATTERN, 'evnt', 'event', trimmed)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** True when input looks like the user is attempting an ID search (including partial). */
|
|
59
|
+
export function looksLikeWorkflowIdSearchInput(query: string): boolean {
|
|
60
|
+
const trimmed = query.trim();
|
|
61
|
+
if (!WORKFLOW_ID_PREFIX_PATTERN.test(trimmed)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// Distinguish IDs (contain digits) from event-type strings like step_started.
|
|
65
|
+
// Assumes workflow event types do not include digits in their names.
|
|
66
|
+
return /\d/.test(trimmed);
|
|
67
|
+
}
|