@workflow/web-shared 5.0.0-beta.0 → 5.0.0-beta.2
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.map +1 -1
- package/dist/components/event-list-view.d.ts +3 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +76 -70
- package/dist/components/event-list-view.js.map +1 -1
- package/dist/components/hook-actions.js.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/index.js.map +1 -1
- 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 +2 -2
- package/dist/components/run-trace-view.js.map +1 -1
- 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 +36 -26
- package/dist/components/sidebar/attribute-panel.js.map +1 -1
- package/dist/components/sidebar/conversation-view.js.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js.map +1 -1
- package/dist/components/sidebar/detail-card.js.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts +5 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +18 -16
- package/dist/components/sidebar/entity-detail-panel.js.map +1 -1
- package/dist/components/sidebar/events-list.d.ts +1 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +26 -18
- package/dist/components/sidebar/events-list.js.map +1 -1
- package/dist/components/sidebar/resolve-hook-modal.js.map +1 -1
- package/dist/components/stream-viewer.js.map +1 -1
- package/dist/components/trace-viewer/components/map.js.map +1 -1
- package/dist/components/trace-viewer/components/markers.js.map +1 -1
- package/dist/components/trace-viewer/components/node.js.map +1 -1
- package/dist/components/trace-viewer/components/search-input.js.map +1 -1
- package/dist/components/trace-viewer/components/search.js.map +1 -1
- package/dist/components/trace-viewer/components/span-content.js.map +1 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +1 -1
- package/dist/components/trace-viewer/components/span-segments.js.map +1 -1
- package/dist/components/trace-viewer/components/span-strategies.js.map +1 -1
- package/dist/components/trace-viewer/components/ui.js.map +1 -1
- package/dist/components/trace-viewer/components/zoom-button.js.map +1 -1
- package/dist/components/trace-viewer/components/zoom-icons.js.map +1 -1
- package/dist/components/trace-viewer/context.js.map +1 -1
- package/dist/components/trace-viewer/index.js.map +1 -1
- package/dist/components/trace-viewer/trace-viewer.js.map +1 -1
- package/dist/components/trace-viewer/types.js.map +1 -1
- package/dist/components/trace-viewer/util/constants.js.map +1 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +1 -1
- package/dist/components/trace-viewer/util/timing.js.map +1 -1
- package/dist/components/trace-viewer/util/tree.js.map +1 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +1 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +1 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +1 -1
- package/dist/components/trace-viewer/worker.js.map +1 -1
- package/dist/components/ui/alert.js.map +1 -1
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/data-inspector.d.ts +17 -1
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +116 -21
- package/dist/components/ui/data-inspector.js.map +1 -1
- package/dist/components/ui/decrypt-button.js.map +1 -1
- package/dist/components/ui/error-card.js.map +1 -1
- package/dist/components/ui/error-stack-block.js.map +1 -1
- package/dist/components/ui/inspector-theme.js.map +1 -1
- package/dist/components/ui/load-more-button.js.map +1 -1
- package/dist/components/ui/menu-dropdown.js.map +1 -1
- package/dist/components/ui/skeleton.js.map +1 -1
- package/dist/components/ui/spinner.js.map +1 -1
- package/dist/components/ui/timestamp-tooltip.js.map +1 -1
- package/dist/components/workflow-trace-view.d.ts +5 -1
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +7 -2
- package/dist/components/workflow-trace-view.js.map +1 -1
- package/dist/components/workflow-traces/event-colors.js.map +1 -1
- package/dist/components/workflow-traces/trace-colors.js.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js.map +1 -1
- package/dist/components/workflow-traces/trace-time-utils.js.map +1 -1
- package/dist/hooks/use-dark-mode.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/event-analysis.js.map +1 -1
- package/dist/lib/event-materialization.js.map +1 -1
- package/dist/lib/hydration.d.ts +9 -2
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +43 -14
- package/dist/lib/hydration.js.map +1 -1
- package/dist/lib/toast.js.map +1 -1
- package/dist/lib/trace-builder.js.map +1 -1
- package/dist/lib/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/components/event-list-view.tsx +207 -193
- package/src/components/index.ts +6 -1
- package/src/components/run-trace-view.tsx +3 -0
- package/src/components/sidebar/attribute-panel.tsx +160 -109
- package/src/components/sidebar/entity-detail-panel.tsx +111 -96
- package/src/components/sidebar/events-list.tsx +42 -32
- package/src/components/ui/data-inspector.tsx +205 -31
- package/src/components/workflow-trace-view.tsx +14 -0
- package/src/components/workflow-traces/trace-span-construction.ts +1 -1
- package/src/index.ts +1 -0
- package/src/lib/hydration.ts +50 -13
|
@@ -5,17 +5,22 @@ import type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
|
|
|
5
5
|
import type { ModelMessage } from 'ai';
|
|
6
6
|
import { Lock } from 'lucide-react';
|
|
7
7
|
import type { KeyboardEvent, ReactNode } from 'react';
|
|
8
|
-
import { useCallback, useMemo, useState } from 'react';
|
|
8
|
+
import { useCallback, useContext, useMemo, useState } from 'react';
|
|
9
9
|
import { isEncryptedMarker, isExpiredMarker } from '../../lib/hydration';
|
|
10
10
|
import { useToast } from '../../lib/toast';
|
|
11
11
|
import { extractConversation, isDoStreamStep } from '../../lib/utils';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DecryptClickContext,
|
|
14
|
+
RunClickContext,
|
|
15
|
+
StreamClickContext,
|
|
16
|
+
} from '../ui/data-inspector';
|
|
13
17
|
import { ErrorCard } from '../ui/error-card';
|
|
14
18
|
import {
|
|
15
19
|
ErrorStackBlock,
|
|
16
20
|
isStructuredErrorWithStack,
|
|
17
21
|
} from '../ui/error-stack-block';
|
|
18
22
|
import { Skeleton } from '../ui/skeleton';
|
|
23
|
+
import { Spinner } from '../ui/spinner';
|
|
19
24
|
import { TimestampTooltip } from '../ui/timestamp-tooltip';
|
|
20
25
|
import { ConversationView } from './conversation-view';
|
|
21
26
|
import { CopyableDataBlock } from './copyable-data-block';
|
|
@@ -180,9 +185,36 @@ function ConversationWithTabs({
|
|
|
180
185
|
* with the lucide Lock icon matching the title bar Decrypt button.
|
|
181
186
|
*/
|
|
182
187
|
function EncryptedFieldBlock() {
|
|
188
|
+
const ctx = useContext(DecryptClickContext);
|
|
189
|
+
if (ctx) {
|
|
190
|
+
return (
|
|
191
|
+
<button
|
|
192
|
+
type="button"
|
|
193
|
+
onClick={ctx.onDecrypt}
|
|
194
|
+
disabled={ctx.isDecrypting}
|
|
195
|
+
className="flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs cursor-pointer transition-colors"
|
|
196
|
+
style={{
|
|
197
|
+
borderColor: 'var(--ds-gray-400)',
|
|
198
|
+
backgroundColor: 'var(--ds-gray-100)',
|
|
199
|
+
color: 'var(--ds-gray-700)',
|
|
200
|
+
opacity: ctx.isDecrypting ? 0.6 : 1,
|
|
201
|
+
}}
|
|
202
|
+
title="Click to decrypt"
|
|
203
|
+
>
|
|
204
|
+
{ctx.isDecrypting ? (
|
|
205
|
+
<Spinner size={12} />
|
|
206
|
+
) : (
|
|
207
|
+
<Lock className="h-3 w-3" />
|
|
208
|
+
)}
|
|
209
|
+
<span className="font-medium">
|
|
210
|
+
{ctx.isDecrypting ? 'Decrypting…' : 'Decrypt'}
|
|
211
|
+
</span>
|
|
212
|
+
</button>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
183
215
|
return (
|
|
184
216
|
<div
|
|
185
|
-
className="flex items-center gap-1.5 rounded-md border px-3 py-2 text-xs"
|
|
217
|
+
className="flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs"
|
|
186
218
|
style={{
|
|
187
219
|
borderColor: 'var(--ds-gray-300)',
|
|
188
220
|
backgroundColor: 'var(--ds-gray-100)',
|
|
@@ -377,7 +409,8 @@ const attributeToDisplayFn: Record<
|
|
|
377
409
|
workflowName: (value: unknown) =>
|
|
378
410
|
parseWorkflowName(String(value))?.shortName ?? '?',
|
|
379
411
|
moduleSpecifier: (value: unknown) => getModuleSpecifierFromName(value),
|
|
380
|
-
stepName: (value: unknown) =>
|
|
412
|
+
stepName: (value: unknown) =>
|
|
413
|
+
parseStepName(String(value))?.shortName ?? String(value),
|
|
381
414
|
// IDs
|
|
382
415
|
runId: (value: unknown) => String(value),
|
|
383
416
|
stepId: (value: unknown) => String(value),
|
|
@@ -689,6 +722,9 @@ export const AttributePanel = ({
|
|
|
689
722
|
error,
|
|
690
723
|
expiredAt,
|
|
691
724
|
onStreamClick,
|
|
725
|
+
onRunClick,
|
|
726
|
+
onDecrypt,
|
|
727
|
+
isDecrypting = false,
|
|
692
728
|
resource,
|
|
693
729
|
}: {
|
|
694
730
|
data: Record<string, unknown>;
|
|
@@ -698,6 +734,12 @@ export const AttributePanel = ({
|
|
|
698
734
|
expiredAt?: string | Date;
|
|
699
735
|
/** Callback when a stream reference is clicked */
|
|
700
736
|
onStreamClick?: (streamId: string) => void;
|
|
737
|
+
/** Callback when a run reference is clicked */
|
|
738
|
+
onRunClick?: (runId: string) => void;
|
|
739
|
+
/** Callback when an encrypted marker is clicked (triggers decryption) */
|
|
740
|
+
onDecrypt?: () => void;
|
|
741
|
+
/** Whether decryption is currently in progress */
|
|
742
|
+
isDecrypting?: boolean;
|
|
701
743
|
/** Resource type of the selected span — used to show targeted loading skeletons. */
|
|
702
744
|
resource?: string;
|
|
703
745
|
}) => {
|
|
@@ -797,117 +839,126 @@ export const AttributePanel = ({
|
|
|
797
839
|
}, []);
|
|
798
840
|
|
|
799
841
|
return (
|
|
800
|
-
<
|
|
801
|
-
<
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
842
|
+
<RunClickContext.Provider value={onRunClick}>
|
|
843
|
+
<StreamClickContext.Provider value={onStreamClick}>
|
|
844
|
+
<DecryptClickContext.Provider
|
|
845
|
+
value={onDecrypt ? { onDecrypt, isDecrypting } : undefined}
|
|
846
|
+
>
|
|
847
|
+
<div>
|
|
848
|
+
{/* Basic attributes in a vertical layout with border */}
|
|
849
|
+
{visibleBasicAttributes.length > 0 && (
|
|
850
|
+
<div
|
|
851
|
+
className="mb-3 flex flex-col overflow-hidden rounded-lg border"
|
|
852
|
+
style={{
|
|
853
|
+
borderColor: 'var(--ds-gray-300)',
|
|
854
|
+
}}
|
|
855
|
+
>
|
|
856
|
+
{orderedBasicAttributes.map((attribute, index) => {
|
|
857
|
+
const displayValue = attributeToDisplayFn[
|
|
858
|
+
attribute as keyof typeof attributeToDisplayFn
|
|
859
|
+
]?.(displayData[attribute as keyof typeof displayData]);
|
|
860
|
+
const isModuleSpecifier = attribute === 'moduleSpecifier';
|
|
861
|
+
const moduleSpecifierValue =
|
|
862
|
+
typeof displayValue === 'string'
|
|
863
|
+
? displayValue
|
|
864
|
+
: String(
|
|
865
|
+
displayValue ?? displayData.moduleSpecifier ?? ''
|
|
866
|
+
);
|
|
867
|
+
const shouldCapitalizeLabel =
|
|
868
|
+
attribute !== 'workflowCoreVersion';
|
|
869
|
+
const showResumeAtSkeleton =
|
|
870
|
+
isLoading && resource === 'sleep' && !displayData.resumeAt;
|
|
871
|
+
const showDivider =
|
|
872
|
+
index < orderedBasicAttributes.length - 1 ||
|
|
873
|
+
showResumeAtSkeleton;
|
|
874
|
+
|
|
875
|
+
return (
|
|
876
|
+
<div key={attribute} className="py-1">
|
|
877
|
+
<div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
|
|
878
|
+
<span
|
|
879
|
+
className={
|
|
880
|
+
shouldCapitalizeLabel
|
|
881
|
+
? 'text-[14px] first-letter:uppercase'
|
|
882
|
+
: 'text-[14px]'
|
|
883
|
+
}
|
|
884
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
885
|
+
>
|
|
886
|
+
{getAttributeDisplayName(attribute)}
|
|
887
|
+
</span>
|
|
888
|
+
{isModuleSpecifier ? (
|
|
889
|
+
<button
|
|
890
|
+
type="button"
|
|
891
|
+
className="min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
892
|
+
style={{
|
|
893
|
+
color: 'var(--ds-gray-1000)',
|
|
894
|
+
background: 'transparent',
|
|
895
|
+
border: 'none',
|
|
896
|
+
padding: 0,
|
|
897
|
+
}}
|
|
898
|
+
title={moduleSpecifierValue}
|
|
899
|
+
onClick={() =>
|
|
900
|
+
handleCopyModuleSpecifier(moduleSpecifierValue)
|
|
901
|
+
}
|
|
902
|
+
>
|
|
903
|
+
{moduleSpecifierValue}
|
|
904
|
+
</button>
|
|
905
|
+
) : (
|
|
906
|
+
<span
|
|
907
|
+
className="min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
908
|
+
style={{ color: 'var(--ds-gray-1000)' }}
|
|
909
|
+
>
|
|
910
|
+
{displayValue}
|
|
911
|
+
</span>
|
|
912
|
+
)}
|
|
913
|
+
</div>
|
|
914
|
+
{showDivider ? (
|
|
915
|
+
<div
|
|
916
|
+
className="mx-2.5 border-b"
|
|
917
|
+
style={{ borderColor: 'var(--ds-gray-300)' }}
|
|
918
|
+
/>
|
|
919
|
+
) : null}
|
|
920
|
+
</div>
|
|
921
|
+
);
|
|
922
|
+
})}
|
|
923
|
+
{isLoading && resource === 'sleep' && !displayData.resumeAt && (
|
|
924
|
+
<div className="py-1">
|
|
925
|
+
<div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
|
|
857
926
|
<span
|
|
858
|
-
className="
|
|
859
|
-
style={{ color: 'var(--ds-gray-
|
|
927
|
+
className="text-[14px] first-letter:uppercase"
|
|
928
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
860
929
|
>
|
|
861
|
-
|
|
930
|
+
resumeAt
|
|
862
931
|
</span>
|
|
863
|
-
|
|
932
|
+
<Skeleton className="h-4 w-[55%]" />
|
|
933
|
+
</div>
|
|
864
934
|
</div>
|
|
865
|
-
|
|
866
|
-
<div
|
|
867
|
-
className="mx-2.5 border-b"
|
|
868
|
-
style={{ borderColor: 'var(--ds-gray-300)' }}
|
|
869
|
-
/>
|
|
870
|
-
) : null}
|
|
871
|
-
</div>
|
|
872
|
-
);
|
|
873
|
-
})}
|
|
874
|
-
{isLoading && resource === 'sleep' && !displayData.resumeAt && (
|
|
875
|
-
<div className="py-1">
|
|
876
|
-
<div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
|
|
877
|
-
<span
|
|
878
|
-
className="text-[14px] first-letter:uppercase"
|
|
879
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
880
|
-
>
|
|
881
|
-
resumeAt
|
|
882
|
-
</span>
|
|
883
|
-
<Skeleton className="h-4 w-[55%]" />
|
|
884
|
-
</div>
|
|
935
|
+
)}
|
|
885
936
|
</div>
|
|
886
937
|
)}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
details={error.message}
|
|
893
|
-
className="my-4"
|
|
894
|
-
/>
|
|
895
|
-
) : hasExpired ? (
|
|
896
|
-
<ExpiredDataMessage />
|
|
897
|
-
) : (
|
|
898
|
-
<>
|
|
899
|
-
{resolvedAttributes.map((attribute) => (
|
|
900
|
-
<AttributeBlock
|
|
901
|
-
isLoading={isLoading}
|
|
902
|
-
key={attribute}
|
|
903
|
-
attribute={attribute}
|
|
904
|
-
value={displayData[attribute as keyof typeof displayData]}
|
|
905
|
-
context={displayContext}
|
|
938
|
+
{error ? (
|
|
939
|
+
<ErrorCard
|
|
940
|
+
title="Failed to load resource details"
|
|
941
|
+
details={error.message}
|
|
942
|
+
className="my-4"
|
|
906
943
|
/>
|
|
907
|
-
)
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
944
|
+
) : hasExpired ? (
|
|
945
|
+
<ExpiredDataMessage />
|
|
946
|
+
) : (
|
|
947
|
+
<>
|
|
948
|
+
{resolvedAttributes.map((attribute) => (
|
|
949
|
+
<AttributeBlock
|
|
950
|
+
isLoading={isLoading}
|
|
951
|
+
key={attribute}
|
|
952
|
+
attribute={attribute}
|
|
953
|
+
value={displayData[attribute as keyof typeof displayData]}
|
|
954
|
+
context={displayContext}
|
|
955
|
+
/>
|
|
956
|
+
))}
|
|
957
|
+
</>
|
|
958
|
+
)}
|
|
959
|
+
</div>
|
|
960
|
+
</DecryptClickContext.Provider>
|
|
961
|
+
</StreamClickContext.Provider>
|
|
962
|
+
</RunClickContext.Provider>
|
|
912
963
|
);
|
|
913
964
|
};
|
|
@@ -4,8 +4,9 @@ import type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
|
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
import { Send, Zap } from 'lucide-react';
|
|
6
6
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
|
-
import { useToast } from '../../lib/toast';
|
|
8
7
|
import { isEncryptedMarker } from '../../lib/hydration';
|
|
8
|
+
import { useToast } from '../../lib/toast';
|
|
9
|
+
import { DecryptClickContext } from '../ui/data-inspector';
|
|
9
10
|
import { DecryptButton } from '../ui/decrypt-button';
|
|
10
11
|
import { AttributePanel } from './attribute-panel';
|
|
11
12
|
import { EventsList } from './events-list';
|
|
@@ -56,6 +57,7 @@ export interface SelectedSpanInfo {
|
|
|
56
57
|
export function EntityDetailPanel({
|
|
57
58
|
run,
|
|
58
59
|
onStreamClick,
|
|
60
|
+
onRunClick,
|
|
59
61
|
spanDetailData,
|
|
60
62
|
spanDetailError,
|
|
61
63
|
spanDetailLoading,
|
|
@@ -67,10 +69,13 @@ export function EntityDetailPanel({
|
|
|
67
69
|
onDecrypt,
|
|
68
70
|
isDecrypting = false,
|
|
69
71
|
selectedSpan,
|
|
72
|
+
hasEncryptedData = false,
|
|
70
73
|
}: {
|
|
71
74
|
run: WorkflowRun;
|
|
72
75
|
/** Callback when a stream reference is clicked */
|
|
73
76
|
onStreamClick?: (streamId: string) => void;
|
|
77
|
+
/** Callback when a run reference is clicked */
|
|
78
|
+
onRunClick?: (runId: string) => void;
|
|
74
79
|
/** Pre-fetched span detail data for the selected span. */
|
|
75
80
|
spanDetailData: WorkflowRun | Step | Hook | Event | null;
|
|
76
81
|
/** Error from external span detail fetch. */
|
|
@@ -103,6 +108,8 @@ export function EntityDetailPanel({
|
|
|
103
108
|
isDecrypting?: boolean;
|
|
104
109
|
/** Info about the currently selected span from the trace viewer */
|
|
105
110
|
selectedSpan: SelectedSpanInfo | null;
|
|
111
|
+
/** Run-level hint: the run contains encrypted data (from probe). */
|
|
112
|
+
hasEncryptedData?: boolean;
|
|
106
113
|
}): React.JSX.Element | null {
|
|
107
114
|
const toast = useToast();
|
|
108
115
|
const [stoppingSleep, setStoppingSleep] = useState(false);
|
|
@@ -391,111 +398,119 @@ export function EntityDetailPanel({
|
|
|
391
398
|
{resourceId}
|
|
392
399
|
</p>
|
|
393
400
|
</div>
|
|
394
|
-
{(hasEncryptedFields || encryptionKey) &&
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
+
{(hasEncryptedFields || hasEncryptedData || encryptionKey) &&
|
|
402
|
+
onDecrypt && (
|
|
403
|
+
<DecryptButton
|
|
404
|
+
decrypted={!!encryptionKey}
|
|
405
|
+
loading={isDecrypting}
|
|
406
|
+
onClick={onDecrypt}
|
|
407
|
+
/>
|
|
408
|
+
)}
|
|
401
409
|
</div>
|
|
402
410
|
</div>
|
|
403
411
|
|
|
404
|
-
<
|
|
405
|
-
{
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
412
|
+
<DecryptClickContext.Provider
|
|
413
|
+
value={onDecrypt ? { onDecrypt, isDecrypting } : undefined}
|
|
414
|
+
>
|
|
415
|
+
<div className="flex-1 overflow-y-auto px-3 pt-3 pb-8">
|
|
416
|
+
{hasPendingActions && (
|
|
417
|
+
<div
|
|
418
|
+
className="mb-4 rounded-lg border p-2"
|
|
419
|
+
style={{
|
|
420
|
+
borderColor: 'var(--ds-gray-300)',
|
|
421
|
+
backgroundColor: 'var(--ds-gray-100)',
|
|
422
|
+
}}
|
|
416
423
|
>
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
stoppingSleep
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
resolvingHook
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
424
|
+
<p
|
|
425
|
+
className="mb-2 px-1 text-[13px] font-medium uppercase tracking-wide"
|
|
426
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
427
|
+
>
|
|
428
|
+
Actions
|
|
429
|
+
</p>
|
|
430
|
+
<div className="flex flex-col gap-2">
|
|
431
|
+
{/* Wake up button for pending sleep calls */}
|
|
432
|
+
{resource === 'sleep' && canWakeUp && (
|
|
433
|
+
<button
|
|
434
|
+
type="button"
|
|
435
|
+
onClick={handleWakeUp}
|
|
436
|
+
disabled={stoppingSleep}
|
|
437
|
+
className={clsx(
|
|
438
|
+
'flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium',
|
|
439
|
+
'disabled:opacity-50 disabled:cursor-not-allowed transition-colors',
|
|
440
|
+
stoppingSleep
|
|
441
|
+
? 'opacity-50 cursor-not-allowed'
|
|
442
|
+
: 'cursor-pointer'
|
|
443
|
+
)}
|
|
444
|
+
style={{
|
|
445
|
+
background: 'var(--ds-amber-200)',
|
|
446
|
+
color: 'var(--ds-amber-900)',
|
|
447
|
+
}}
|
|
448
|
+
>
|
|
449
|
+
<Zap className="h-4 w-4" />
|
|
450
|
+
{stoppingSleep ? 'Waking up...' : 'Wake Up Sleep'}
|
|
451
|
+
</button>
|
|
452
|
+
)}
|
|
453
|
+
|
|
454
|
+
{/* Resolve hook button for pending hooks */}
|
|
455
|
+
{resource === 'hook' && canResolveHook && (
|
|
456
|
+
<button
|
|
457
|
+
type="button"
|
|
458
|
+
onClick={() => setShowResolveHookModal(true)}
|
|
459
|
+
disabled={resolvingHook}
|
|
460
|
+
className={clsx(
|
|
461
|
+
'flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium',
|
|
462
|
+
'disabled:opacity-50 disabled:cursor-not-allowed transition-colors',
|
|
463
|
+
resolvingHook
|
|
464
|
+
? 'opacity-50 cursor-not-allowed'
|
|
465
|
+
: 'cursor-pointer'
|
|
466
|
+
)}
|
|
467
|
+
style={{
|
|
468
|
+
background: 'var(--ds-gray-1000)',
|
|
469
|
+
color: 'var(--ds-background-100)',
|
|
470
|
+
}}
|
|
471
|
+
>
|
|
472
|
+
<Send className="h-4 w-4" />
|
|
473
|
+
Resolve Hook
|
|
474
|
+
</button>
|
|
475
|
+
)}
|
|
476
|
+
</div>
|
|
465
477
|
</div>
|
|
466
|
-
|
|
467
|
-
)}
|
|
478
|
+
)}
|
|
468
479
|
|
|
469
|
-
|
|
470
|
-
<section>
|
|
471
|
-
<h3
|
|
472
|
-
className="mb-2 text-[13px] font-medium uppercase tracking-wide"
|
|
473
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
474
|
-
>
|
|
475
|
-
Details
|
|
476
|
-
</h3>
|
|
477
|
-
<AttributePanel
|
|
478
|
-
data={displayData}
|
|
479
|
-
moduleSpecifier={moduleSpecifier}
|
|
480
|
-
expiredAt={run.expiredAt}
|
|
481
|
-
isLoading={loading}
|
|
482
|
-
error={error ?? undefined}
|
|
483
|
-
onStreamClick={onStreamClick}
|
|
484
|
-
resource={resource}
|
|
485
|
-
/>
|
|
486
|
-
</section>
|
|
487
|
-
|
|
488
|
-
{resource !== 'run' && rawEvents && (
|
|
480
|
+
<div className="space-y-4">
|
|
489
481
|
<section>
|
|
490
|
-
<
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
482
|
+
<h3
|
|
483
|
+
className="mb-2 text-[13px] font-medium uppercase tracking-wide"
|
|
484
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
485
|
+
>
|
|
486
|
+
Details
|
|
487
|
+
</h3>
|
|
488
|
+
<AttributePanel
|
|
489
|
+
data={displayData}
|
|
490
|
+
moduleSpecifier={moduleSpecifier}
|
|
491
|
+
expiredAt={run.expiredAt}
|
|
492
|
+
isLoading={loading}
|
|
493
|
+
error={error ?? undefined}
|
|
494
|
+
onStreamClick={onStreamClick}
|
|
495
|
+
onRunClick={onRunClick}
|
|
496
|
+
onDecrypt={onDecrypt}
|
|
497
|
+
isDecrypting={isDecrypting}
|
|
498
|
+
resource={resource}
|
|
494
499
|
/>
|
|
495
500
|
</section>
|
|
496
|
-
|
|
501
|
+
|
|
502
|
+
{resource !== 'run' && rawEvents && (
|
|
503
|
+
<section>
|
|
504
|
+
<EventsList
|
|
505
|
+
events={rawEvents}
|
|
506
|
+
onLoadEventData={onLoadEventData}
|
|
507
|
+
encryptionKey={encryptionKey}
|
|
508
|
+
/>
|
|
509
|
+
</section>
|
|
510
|
+
)}
|
|
511
|
+
</div>
|
|
497
512
|
</div>
|
|
498
|
-
</
|
|
513
|
+
</DecryptClickContext.Provider>
|
|
499
514
|
|
|
500
515
|
{/* Resolve Hook Modal */}
|
|
501
516
|
<ResolveHookModal
|