@rozenite/vite-plugin 1.12.0 → 1.13.0
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/package.json +2 -1
- package/src/bundle-dts.ts +125 -0
- package/src/client-plugin.ts +392 -0
- package/src/dev-config-module.ts +29 -0
- package/src/dev-host/App.tsx +567 -0
- package/src/dev-host/components/DispatchForm.tsx +169 -0
- package/src/dev-host/components/FlowList.tsx +142 -0
- package/src/dev-host/components/MessageDetailsPane.tsx +109 -0
- package/src/dev-host/components/MessageLogPane.tsx +84 -0
- package/src/dev-host/components/MessagePayloadDetail.tsx +32 -0
- package/src/dev-host/components/PanelTabs.tsx +22 -0
- package/src/dev-host/components/ResizeHandle.tsx +33 -0
- package/src/dev-host/components/icons.tsx +79 -0
- package/src/dev-host/components/ui/Button.tsx +91 -0
- package/src/dev-host/components/ui/DropdownMenu.tsx +84 -0
- package/src/dev-host/components/ui/IconButton.tsx +41 -0
- package/src/dev-host/components/ui/Input.tsx +73 -0
- package/src/dev-host/components/ui/ScrollArea.tsx +20 -0
- package/src/dev-host/components/ui/Tabs.tsx +166 -0
- package/src/dev-host/components/ui/Textarea.tsx +79 -0
- package/src/dev-host/components/ui/ToggleGroup.tsx +120 -0
- package/src/dev-host/config.ts +107 -0
- package/src/dev-host/constants.ts +31 -0
- package/src/dev-host/flow-runtime.ts +297 -0
- package/src/dev-host/index.html +12 -0
- package/src/dev-host/main.tsx +31 -0
- package/src/dev-host/server.ts +55 -0
- package/src/dev-host/styles.css +969 -0
- package/src/dev-host/types.ts +61 -0
- package/src/dev-host/utils.ts +96 -0
- package/src/dev-host/vite.config.mts +20 -0
- package/src/index.ts +114 -0
- package/src/load-config.ts +117 -0
- package/src/package-json.ts +16 -0
- package/src/react-native-plugin.ts +49 -0
- package/src/require-plugin.ts +221 -0
- package/src/sdk-plugin.ts +44 -0
- package/src/server-plugin.ts +36 -0
- package/src/utils.ts +31 -0
- package/src/virtual-modules.d.ts +7 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { useState, type FormEvent } from 'react';
|
|
2
|
+
import type { DevHostFlowEntry, DevHostFlowRunState, DevHostPresetEntry } from '../types.js';
|
|
3
|
+
import { ClearIcon, PresetsIcon, SendIcon } from './icons.js';
|
|
4
|
+
import { FlowList } from './FlowList.js';
|
|
5
|
+
import { DropdownMenu, type DropdownMenuItem } from './ui/DropdownMenu.js';
|
|
6
|
+
import { IconButton } from './ui/IconButton.js';
|
|
7
|
+
import { Input } from './ui/Input.js';
|
|
8
|
+
import { ScrollArea } from './ui/ScrollArea.js';
|
|
9
|
+
import { Textarea } from './ui/Textarea.js';
|
|
10
|
+
import { ToggleGroup } from './ui/ToggleGroup.js';
|
|
11
|
+
|
|
12
|
+
type DispatchFormProps = {
|
|
13
|
+
commandType: string;
|
|
14
|
+
commandPayload: string;
|
|
15
|
+
flows: DevHostFlowEntry[];
|
|
16
|
+
flowRuns: DevHostFlowRunState[];
|
|
17
|
+
hasRunningFlow: (flowName: string) => boolean;
|
|
18
|
+
presets: DevHostPresetEntry[];
|
|
19
|
+
canDispatch: boolean;
|
|
20
|
+
onRunFlow: (flow: DevHostFlowEntry) => void;
|
|
21
|
+
onStopFlow: (runId: string) => void;
|
|
22
|
+
onCommandTypeChange: (value: string) => void;
|
|
23
|
+
onCommandPayloadChange: (value: string) => void;
|
|
24
|
+
onApplyPreset: (preset: DevHostPresetEntry) => void;
|
|
25
|
+
onReset: () => void;
|
|
26
|
+
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const DispatchForm = ({
|
|
30
|
+
commandType,
|
|
31
|
+
commandPayload,
|
|
32
|
+
flows,
|
|
33
|
+
flowRuns,
|
|
34
|
+
hasRunningFlow,
|
|
35
|
+
presets,
|
|
36
|
+
canDispatch,
|
|
37
|
+
onRunFlow,
|
|
38
|
+
onStopFlow,
|
|
39
|
+
onCommandTypeChange,
|
|
40
|
+
onCommandPayloadChange,
|
|
41
|
+
onApplyPreset,
|
|
42
|
+
onReset,
|
|
43
|
+
onSubmit,
|
|
44
|
+
}: DispatchFormProps) => {
|
|
45
|
+
const [activeTab, setActiveTab] = useState<'dispatch' | 'flows'>('dispatch');
|
|
46
|
+
const presetItems: DropdownMenuItem<DevHostPresetEntry>[] = presets.map((preset) => ({
|
|
47
|
+
id: preset.displayName,
|
|
48
|
+
label: preset.displayName,
|
|
49
|
+
item: preset,
|
|
50
|
+
}));
|
|
51
|
+
const presetButton = (
|
|
52
|
+
<IconButton
|
|
53
|
+
type="button"
|
|
54
|
+
variant="default"
|
|
55
|
+
aria-label={presets.length > 0 ? 'Open presets' : 'No presets available'}
|
|
56
|
+
title={presets.length > 0 ? 'Presets' : 'No presets available'}
|
|
57
|
+
disabled={presets.length === 0}
|
|
58
|
+
overrides={{
|
|
59
|
+
BaseButton: {
|
|
60
|
+
style: {
|
|
61
|
+
borderRadius: '6px',
|
|
62
|
+
backgroundColor: 'rgba(255, 255, 255, 0.04)',
|
|
63
|
+
color: 'rgba(255, 255, 255, 0.88)',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<PresetsIcon />
|
|
69
|
+
</IconButton>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div className="rz-pane">
|
|
74
|
+
<div className="rz-sidebar">
|
|
75
|
+
<div className="rz-sidebar-header">
|
|
76
|
+
<div className="rz-sidebar-title">Actions</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<ScrollArea className="rz-sidebar-scroll">
|
|
80
|
+
<div className="rz-action-tabs rz-command-form">
|
|
81
|
+
<div className="rz-action-tabs-header">
|
|
82
|
+
<ToggleGroup
|
|
83
|
+
aria-label="Action modes"
|
|
84
|
+
value={activeTab}
|
|
85
|
+
onChange={(value) => setActiveTab(value as 'dispatch' | 'flows')}
|
|
86
|
+
options={[
|
|
87
|
+
{ key: 'dispatch', label: 'Dispatch' },
|
|
88
|
+
{ key: 'flows', label: 'Flows' },
|
|
89
|
+
]}
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
{activeTab === 'dispatch'
|
|
93
|
+
? presets.length > 0
|
|
94
|
+
? <DropdownMenu items={presetItems} onSelect={onApplyPreset}>{presetButton}</DropdownMenu>
|
|
95
|
+
: presetButton
|
|
96
|
+
: null}
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
{activeTab === 'dispatch' ? (
|
|
100
|
+
<div className="rz-action-tab-panel">
|
|
101
|
+
<form className="rz-action-form" onSubmit={onSubmit}>
|
|
102
|
+
<div className="rz-field">
|
|
103
|
+
<label className="rz-label" htmlFor="command-type">
|
|
104
|
+
Command
|
|
105
|
+
</label>
|
|
106
|
+
<Input
|
|
107
|
+
id="command-type"
|
|
108
|
+
value={commandType}
|
|
109
|
+
onChange={(event) => onCommandTypeChange(event.currentTarget.value)}
|
|
110
|
+
placeholder="get-snapshot"
|
|
111
|
+
spellCheck={false}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div className="rz-field">
|
|
116
|
+
<label className="rz-label" htmlFor="command-payload">
|
|
117
|
+
Payload
|
|
118
|
+
</label>
|
|
119
|
+
<Textarea
|
|
120
|
+
id="command-payload"
|
|
121
|
+
value={commandPayload}
|
|
122
|
+
onChange={(event) => onCommandPayloadChange(event.currentTarget.value)}
|
|
123
|
+
placeholder='{"example": true}'
|
|
124
|
+
spellCheck={false}
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div className="rz-button-row">
|
|
129
|
+
<IconButton
|
|
130
|
+
type="button"
|
|
131
|
+
variant="default"
|
|
132
|
+
aria-label="Reset dispatcher"
|
|
133
|
+
title="Reset dispatcher"
|
|
134
|
+
onClick={onReset}
|
|
135
|
+
>
|
|
136
|
+
<ClearIcon />
|
|
137
|
+
</IconButton>
|
|
138
|
+
|
|
139
|
+
<IconButton
|
|
140
|
+
type="submit"
|
|
141
|
+
variant="primary"
|
|
142
|
+
aria-label="Dispatch message"
|
|
143
|
+
title="Dispatch message"
|
|
144
|
+
disabled={!canDispatch}
|
|
145
|
+
>
|
|
146
|
+
<SendIcon />
|
|
147
|
+
</IconButton>
|
|
148
|
+
</div>
|
|
149
|
+
</form>
|
|
150
|
+
</div>
|
|
151
|
+
) : null}
|
|
152
|
+
|
|
153
|
+
{activeTab === 'flows' ? (
|
|
154
|
+
<div className="rz-action-tab-panel">
|
|
155
|
+
<FlowList
|
|
156
|
+
flows={flows}
|
|
157
|
+
flowRuns={flowRuns}
|
|
158
|
+
hasRunningFlow={hasRunningFlow}
|
|
159
|
+
onRunFlow={onRunFlow}
|
|
160
|
+
onStopFlow={onStopFlow}
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
) : null}
|
|
164
|
+
</div>
|
|
165
|
+
</ScrollArea>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { formatPayloadForCommandInput } from '../utils.js';
|
|
2
|
+
import type { DevHostFlowEntry, DevHostFlowRunState } from '../types.js';
|
|
3
|
+
import { Button } from './ui/Button.js';
|
|
4
|
+
|
|
5
|
+
type FlowListProps = {
|
|
6
|
+
flows: DevHostFlowEntry[];
|
|
7
|
+
flowRuns: DevHostFlowRunState[];
|
|
8
|
+
hasRunningFlow: (flowName: string) => boolean;
|
|
9
|
+
onRunFlow: (flow: DevHostFlowEntry) => void;
|
|
10
|
+
onStopFlow: (runId: string) => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const getStatusLabel = (status: DevHostFlowRunState['status']) => {
|
|
14
|
+
if (status === 'running') {
|
|
15
|
+
return 'Running';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (status === 'succeeded') {
|
|
19
|
+
return 'Completed';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (status === 'failed') {
|
|
23
|
+
return 'Failed';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (status === 'aborted') {
|
|
27
|
+
return 'Stopped';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return status;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const FlowList = ({ flows, flowRuns, hasRunningFlow, onRunFlow, onStopFlow }: FlowListProps) => {
|
|
34
|
+
if (flows.length === 0) {
|
|
35
|
+
return <div className="rz-flow-empty-state">No flows were configured for this plugin.</div>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const hasExecutionState = flowRuns.length > 0;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className="rz-flow-panel">
|
|
42
|
+
<div className="rz-field">
|
|
43
|
+
<div className="rz-label">Available flows</div>
|
|
44
|
+
|
|
45
|
+
<div className="rz-flow-list">
|
|
46
|
+
{flows.map((flow, index) => {
|
|
47
|
+
const isActive = hasRunningFlow(flow.name);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Button
|
|
51
|
+
key={`${flow.name}-${index}`}
|
|
52
|
+
type="button"
|
|
53
|
+
onClick={() => onRunFlow(flow)}
|
|
54
|
+
variant="default"
|
|
55
|
+
isSelected={isActive}
|
|
56
|
+
title={`Run ${flow.displayName}`}
|
|
57
|
+
overrides={{
|
|
58
|
+
BaseButton: {
|
|
59
|
+
style: {
|
|
60
|
+
display: 'flex',
|
|
61
|
+
alignItems: 'center',
|
|
62
|
+
justifyContent: 'space-between',
|
|
63
|
+
gap: '12px',
|
|
64
|
+
width: '100%',
|
|
65
|
+
borderRadius: '8px',
|
|
66
|
+
backgroundColor: isActive ? 'rgba(130, 50, 255, 0.14)' : 'rgba(255, 255, 255, 0.03)',
|
|
67
|
+
borderColor: isActive ? 'rgba(130, 50, 255, 0.45)' : 'rgba(255, 255, 255, 0.08)',
|
|
68
|
+
color: 'rgba(255, 255, 255, 0.88)',
|
|
69
|
+
paddingTop: '10px',
|
|
70
|
+
paddingRight: '12px',
|
|
71
|
+
paddingBottom: '10px',
|
|
72
|
+
paddingLeft: '12px',
|
|
73
|
+
textAlign: 'left',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
<span className="rz-flow-list-name">
|
|
79
|
+
{flow.displayName}
|
|
80
|
+
{flow.autoRun ? <span className="rz-flow-list-badge">Auto</span> : null}
|
|
81
|
+
</span>
|
|
82
|
+
<span className="rz-flow-list-action">{isActive ? 'Running' : 'Run'}</span>
|
|
83
|
+
</Button>
|
|
84
|
+
);
|
|
85
|
+
})}
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
{hasExecutionState ? (
|
|
90
|
+
<div className="rz-field">
|
|
91
|
+
<div className="rz-label">Flow runs</div>
|
|
92
|
+
|
|
93
|
+
<div className="rz-flow-runs">
|
|
94
|
+
{flowRuns.map((flowRun) => {
|
|
95
|
+
const isRunning = flowRun.status === 'running';
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div key={flowRun.id} className="rz-flow-state" data-status={flowRun.status}>
|
|
99
|
+
<div className="rz-flow-state-header">
|
|
100
|
+
<div className="rz-flow-state-title">
|
|
101
|
+
{flowRun.flowDisplayName}
|
|
102
|
+
{flowRun.autoRun ? <span className="rz-flow-state-badge">Auto</span> : null}
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
{isRunning ? (
|
|
106
|
+
<Button
|
|
107
|
+
type="button"
|
|
108
|
+
variant="pill"
|
|
109
|
+
onClick={() => onStopFlow(flowRun.id)}
|
|
110
|
+
overrides={{
|
|
111
|
+
BaseButton: {
|
|
112
|
+
style: {
|
|
113
|
+
flexShrink: 0,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
Stop
|
|
119
|
+
</Button>
|
|
120
|
+
) : null}
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div className="rz-flow-state-status">{getStatusLabel(flowRun.status)}</div>
|
|
124
|
+
|
|
125
|
+
{flowRun.error ? (
|
|
126
|
+
<div className="rz-flow-state-error">{flowRun.error}</div>
|
|
127
|
+
) : null}
|
|
128
|
+
|
|
129
|
+
{flowRun.result != null ? (
|
|
130
|
+
<pre className="rz-flow-state-result">
|
|
131
|
+
{formatPayloadForCommandInput(flowRun.result)}
|
|
132
|
+
</pre>
|
|
133
|
+
) : null}
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
})}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
) : null}
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { PointerEvent as ReactPointerEvent } from 'react';
|
|
2
|
+
import type { MessageEntry, ResizeHandleId } from '../types.js';
|
|
3
|
+
import { formatMessageDate, formatPayloadForCommandInput } from '../utils.js';
|
|
4
|
+
import { MessagePayloadDetail } from './MessagePayloadDetail.js';
|
|
5
|
+
import { ResizeHandle } from './ResizeHandle.js';
|
|
6
|
+
import { ScrollArea } from './ui/ScrollArea.js';
|
|
7
|
+
import { SendIcon } from './icons.js';
|
|
8
|
+
import { IconButton } from './ui/IconButton.js';
|
|
9
|
+
|
|
10
|
+
type MessageDetailsPaneProps = {
|
|
11
|
+
selectedMessage: MessageEntry | null;
|
|
12
|
+
isOpen: boolean;
|
|
13
|
+
isNarrowViewport: boolean;
|
|
14
|
+
activeResizeHandle: ResizeHandleId | null;
|
|
15
|
+
onClose: () => void;
|
|
16
|
+
onUseMessage: (message: MessageEntry) => void;
|
|
17
|
+
onResizeStart: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const MessageDetailsPane = ({
|
|
21
|
+
selectedMessage,
|
|
22
|
+
isOpen,
|
|
23
|
+
isNarrowViewport,
|
|
24
|
+
activeResizeHandle,
|
|
25
|
+
onClose,
|
|
26
|
+
onUseMessage,
|
|
27
|
+
onResizeStart,
|
|
28
|
+
}: MessageDetailsPaneProps) => {
|
|
29
|
+
const isHidden = !isOpen || !selectedMessage;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
{!isNarrowViewport ? (
|
|
34
|
+
<ResizeHandle
|
|
35
|
+
className="rz-column-resize-handle"
|
|
36
|
+
isDragging={activeResizeHandle === 'details-width'}
|
|
37
|
+
isHidden={isHidden}
|
|
38
|
+
orientation="vertical"
|
|
39
|
+
label="Resize message details"
|
|
40
|
+
onPointerDown={onResizeStart}
|
|
41
|
+
/>
|
|
42
|
+
) : null}
|
|
43
|
+
|
|
44
|
+
<div className="rz-pane" data-hidden={isHidden} aria-hidden={isHidden}>
|
|
45
|
+
<div className="rz-sidebar">
|
|
46
|
+
<div className="rz-sidebar-header">
|
|
47
|
+
<div className="rz-sidebar-title">Message Details</div>
|
|
48
|
+
<div className="rz-header-actions">
|
|
49
|
+
<IconButton
|
|
50
|
+
type="button"
|
|
51
|
+
aria-label="Use message in dispatcher"
|
|
52
|
+
title="Use message in dispatcher"
|
|
53
|
+
onClick={() => {
|
|
54
|
+
if (selectedMessage) {
|
|
55
|
+
onUseMessage(selectedMessage);
|
|
56
|
+
}
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<SendIcon />
|
|
60
|
+
</IconButton>
|
|
61
|
+
|
|
62
|
+
<IconButton
|
|
63
|
+
type="button"
|
|
64
|
+
aria-label="Close message details"
|
|
65
|
+
onClick={onClose}
|
|
66
|
+
>
|
|
67
|
+
×
|
|
68
|
+
</IconButton>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<ScrollArea className="rz-sidebar-scroll">
|
|
73
|
+
{selectedMessage ? (
|
|
74
|
+
<div className="rz-message-detail">
|
|
75
|
+
<div className="rz-detail-section">
|
|
76
|
+
<div className="rz-label">Date</div>
|
|
77
|
+
<div className="rz-detail-value rz-detail-mono">
|
|
78
|
+
{formatMessageDate(selectedMessage.date)}
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div className="rz-detail-section">
|
|
83
|
+
<div className="rz-label">Type</div>
|
|
84
|
+
<div className="rz-detail-value rz-detail-mono">{selectedMessage.type}</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div className="rz-detail-section">
|
|
88
|
+
<div className="rz-label">Payload</div>
|
|
89
|
+
<div className="rz-detail-payload">
|
|
90
|
+
<MessagePayloadDetail payload={selectedMessage.payload} />
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
) : (
|
|
95
|
+
<div className="rz-empty-state">Select a message to inspect its details.</div>
|
|
96
|
+
)}
|
|
97
|
+
</ScrollArea>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const getDispatcherValuesFromMessage = (message: MessageEntry) => {
|
|
105
|
+
return {
|
|
106
|
+
commandType: message.type,
|
|
107
|
+
commandPayload: formatPayloadForCommandInput(message.payload),
|
|
108
|
+
};
|
|
109
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { MessageEntry } from '../types.js';
|
|
2
|
+
import { cn, formatMessageTableDate, formatPayloadPreview } from '../utils.js';
|
|
3
|
+
import { ClearIcon } from './icons.js';
|
|
4
|
+
import { ScrollArea } from './ui/ScrollArea.js';
|
|
5
|
+
import { IconButton } from './ui/IconButton.js';
|
|
6
|
+
|
|
7
|
+
type MessageLogPaneProps = {
|
|
8
|
+
messages: MessageEntry[];
|
|
9
|
+
selectedMessageId: string | null;
|
|
10
|
+
onSelectMessage: (messageId: string) => void;
|
|
11
|
+
onClearMessages: () => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const MessageLogPane = ({
|
|
15
|
+
messages,
|
|
16
|
+
selectedMessageId,
|
|
17
|
+
onSelectMessage,
|
|
18
|
+
onClearMessages,
|
|
19
|
+
}: MessageLogPaneProps) => {
|
|
20
|
+
return (
|
|
21
|
+
<div className="rz-pane">
|
|
22
|
+
<div className="rz-log-pane">
|
|
23
|
+
<div className="rz-sidebar-header">
|
|
24
|
+
<div className="rz-sidebar-title">Message Log</div>
|
|
25
|
+
<div className="rz-header-actions">
|
|
26
|
+
<IconButton
|
|
27
|
+
type="button"
|
|
28
|
+
onClick={onClearMessages}
|
|
29
|
+
disabled={messages.length === 0}
|
|
30
|
+
aria-label="Clear message log"
|
|
31
|
+
title="Clear message log"
|
|
32
|
+
>
|
|
33
|
+
<ClearIcon />
|
|
34
|
+
</IconButton>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<ScrollArea className="rz-sidebar-scroll">
|
|
39
|
+
<div className="rz-message-list">
|
|
40
|
+
<div className="rz-message-list-header">
|
|
41
|
+
<div className="rz-message-header-cell">Dir</div>
|
|
42
|
+
<div className="rz-message-header-cell">Date</div>
|
|
43
|
+
<div className="rz-message-header-cell">Type</div>
|
|
44
|
+
<div className="rz-message-header-cell">Payload</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
{messages.map((message) => (
|
|
48
|
+
<button
|
|
49
|
+
key={message.id}
|
|
50
|
+
type="button"
|
|
51
|
+
className="rz-message-row"
|
|
52
|
+
data-selected={message.id === selectedMessageId}
|
|
53
|
+
onClick={() => onSelectMessage(message.id)}
|
|
54
|
+
>
|
|
55
|
+
<div
|
|
56
|
+
className={cn(
|
|
57
|
+
'rz-message-cell rz-message-direction',
|
|
58
|
+
message.direction === 'in' ? 'rz-message-dir-in' : 'rz-message-dir-out',
|
|
59
|
+
)}
|
|
60
|
+
aria-label={message.direction === 'in' ? 'Sent message' : 'Received message'}
|
|
61
|
+
title={message.direction === 'in' ? 'Sent message' : 'Received message'}
|
|
62
|
+
>
|
|
63
|
+
<span className="rz-message-arrow" aria-hidden="true">
|
|
64
|
+
{message.direction === 'in' ? '↑' : '↓'}
|
|
65
|
+
</span>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div className="rz-message-cell rz-message-date">
|
|
69
|
+
{formatMessageTableDate(message.date)}
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<div className="rz-message-cell rz-message-type">{message.type}</div>
|
|
73
|
+
|
|
74
|
+
<pre className="rz-message-cell rz-message-preview">
|
|
75
|
+
{formatPayloadPreview(message.payload)}
|
|
76
|
+
</pre>
|
|
77
|
+
</button>
|
|
78
|
+
))}
|
|
79
|
+
</div>
|
|
80
|
+
</ScrollArea>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { JSONTree } from 'react-json-tree';
|
|
2
|
+
import { jsonTreeTheme } from '../constants.js';
|
|
3
|
+
import { isJsonTreeData } from '../utils.js';
|
|
4
|
+
|
|
5
|
+
type MessagePayloadDetailProps = {
|
|
6
|
+
payload: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const MessagePayloadDetail = ({ payload }: MessagePayloadDetailProps) => {
|
|
10
|
+
if (typeof payload === 'string') {
|
|
11
|
+
return <pre className="rz-detail-pre rz-detail-mono">{payload}</pre>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof payload === 'number' || typeof payload === 'boolean' || payload == null) {
|
|
15
|
+
return <pre className="rz-detail-pre rz-detail-mono">{String(payload)}</pre>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (isJsonTreeData(payload)) {
|
|
19
|
+
return (
|
|
20
|
+
<div className="rz-detail-json-tree">
|
|
21
|
+
<JSONTree
|
|
22
|
+
data={payload}
|
|
23
|
+
theme={jsonTreeTheme}
|
|
24
|
+
invertTheme={false}
|
|
25
|
+
shouldExpandNodeInitially={(keyPath) => keyPath.length <= 2}
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return <pre className="rz-detail-pre rz-detail-mono">{String(payload)}</pre>;
|
|
32
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DevHostPanelEntry } from '../types.js';
|
|
2
|
+
import { ToggleGroup } from './ui/ToggleGroup.js';
|
|
3
|
+
|
|
4
|
+
type PanelTabsProps = {
|
|
5
|
+
panels: DevHostPanelEntry[];
|
|
6
|
+
activeSource: string;
|
|
7
|
+
onValueChange: (value: string) => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const PanelTabs = ({ panels, activeSource, onValueChange }: PanelTabsProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<ToggleGroup
|
|
13
|
+
aria-label="Plugin panels"
|
|
14
|
+
value={activeSource}
|
|
15
|
+
onChange={onValueChange}
|
|
16
|
+
options={panels.map((panel) => ({
|
|
17
|
+
key: panel.source,
|
|
18
|
+
label: panel.label,
|
|
19
|
+
}))}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { PointerEvent as ReactPointerEvent } from 'react';
|
|
2
|
+
import { cn } from '../utils.js';
|
|
3
|
+
|
|
4
|
+
type ResizeHandleProps = {
|
|
5
|
+
className?: string;
|
|
6
|
+
isDragging: boolean;
|
|
7
|
+
isHidden?: boolean;
|
|
8
|
+
orientation: 'horizontal' | 'vertical';
|
|
9
|
+
label: string;
|
|
10
|
+
onPointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const ResizeHandle = ({
|
|
14
|
+
className,
|
|
15
|
+
isDragging,
|
|
16
|
+
isHidden = false,
|
|
17
|
+
orientation,
|
|
18
|
+
label,
|
|
19
|
+
onPointerDown,
|
|
20
|
+
}: ResizeHandleProps) => {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
className={cn(className)}
|
|
24
|
+
data-dragging={isDragging}
|
|
25
|
+
data-hidden={isHidden}
|
|
26
|
+
aria-hidden={isHidden}
|
|
27
|
+
onPointerDown={onPointerDown}
|
|
28
|
+
role="separator"
|
|
29
|
+
aria-orientation={orientation}
|
|
30
|
+
aria-label={label}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export const ClearIcon = () => {
|
|
2
|
+
return (
|
|
3
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
|
|
4
|
+
<path
|
|
5
|
+
d="M2.5 3.5H11.5M5.5 1.75H8.5M4 3.5V10.5C4 10.9641 4.18437 11.4092 4.51256 11.7374C4.84075 12.0656 5.28587 12.25 5.75 12.25H8.25C8.71413 12.25 9.15925 12.0656 9.48744 11.7374C9.81563 11.4092 10 10.9641 10 10.5V3.5M5.75 5.5V9.625M8.25 5.5V9.625"
|
|
6
|
+
stroke="currentColor"
|
|
7
|
+
strokeWidth="1.25"
|
|
8
|
+
strokeLinecap="round"
|
|
9
|
+
strokeLinejoin="round"
|
|
10
|
+
/>
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const SendIcon = () => {
|
|
16
|
+
return (
|
|
17
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
|
|
18
|
+
<path
|
|
19
|
+
d="M12.25 1.75L6.75 7.25M12.25 1.75L8.75 12.25L6.75 7.25M12.25 1.75L1.75 5.25L6.75 7.25"
|
|
20
|
+
stroke="currentColor"
|
|
21
|
+
strokeWidth="1.25"
|
|
22
|
+
strokeLinecap="round"
|
|
23
|
+
strokeLinejoin="round"
|
|
24
|
+
/>
|
|
25
|
+
</svg>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const ChevronDownIcon = () => {
|
|
30
|
+
return (
|
|
31
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
|
|
32
|
+
<path
|
|
33
|
+
d="M3.5 5.25L7 8.75L10.5 5.25"
|
|
34
|
+
stroke="currentColor"
|
|
35
|
+
strokeWidth="1.25"
|
|
36
|
+
strokeLinecap="round"
|
|
37
|
+
strokeLinejoin="round"
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const PresetsIcon = () => {
|
|
44
|
+
return (
|
|
45
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
|
|
46
|
+
<path
|
|
47
|
+
d="M2.5 3.5H11.5M2.5 7H8.5M2.5 10.5H6.5"
|
|
48
|
+
stroke="currentColor"
|
|
49
|
+
strokeWidth="1.25"
|
|
50
|
+
strokeLinecap="round"
|
|
51
|
+
/>
|
|
52
|
+
<circle cx="10.5" cy="7" r="1" fill="currentColor" />
|
|
53
|
+
<circle cx="8.5" cy="10.5" r="1" fill="currentColor" />
|
|
54
|
+
<circle cx="9.5" cy="3.5" r="1" fill="currentColor" />
|
|
55
|
+
</svg>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const RozeniteLogo = () => {
|
|
60
|
+
return (
|
|
61
|
+
<svg
|
|
62
|
+
width="173"
|
|
63
|
+
height="32"
|
|
64
|
+
viewBox="0 0 172.5 32"
|
|
65
|
+
fill="none"
|
|
66
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
67
|
+
aria-hidden="true"
|
|
68
|
+
>
|
|
69
|
+
<path
|
|
70
|
+
d="M17.333 5.33301H20V10.667H22.667V16H25.333V24H22.667V26.667H20V29.333H12V26.667H9.33301V24H6.66699V16H9.33301V10.667H12V5.33301H14.667V2.66699H17.333V5.33301Z"
|
|
71
|
+
fill="#fff"
|
|
72
|
+
/>
|
|
73
|
+
<path
|
|
74
|
+
d="M51.7354 28H48.1421V3.94287H59.8887C62.1875 3.94287 63.9385 4.56592 65.1416 5.81201C66.3447 7.05811 66.9463 8.80908 66.9463 11.0649C66.9463 12.4829 66.6294 13.6968 65.9956 14.7065C65.3618 15.7163 64.5024 16.4199 63.4175 16.8174V17.043H64.6421C66.2212 17.043 67.0107 17.9023 67.0107 19.6211V28H63.3853V18.9282H51.7354V28ZM51.7354 7.08496V15.915H59.083C60.3398 15.915 61.3228 15.6089 62.0317 14.9966C62.7515 14.3735 63.1113 13.5356 63.1113 12.4829V10.4849C63.1113 9.37842 62.7568 8.53516 62.0479 7.95508C61.3496 7.375 60.3613 7.08496 59.083 7.08496H51.7354ZM70.7187 25.9214C69.2256 24.2993 68.479 22.0972 68.479 19.3149C68.479 16.5327 69.2363 14.3359 70.751 12.7246C72.2656 11.1133 74.312 10.3076 76.8901 10.3076C79.393 10.3076 81.4179 11.1133 82.9648 12.7246C84.5224 14.3145 85.3013 16.5112 85.3013 19.3149C85.3013 22.0757 84.5547 24.2671 83.0615 25.8892C81.5683 27.5112 79.5112 28.3223 76.8901 28.3223C74.2798 28.3223 72.2226 27.522 70.7187 25.9214ZM71.9433 18.042V20.7329C71.9433 22.2153 72.3999 23.3809 73.313 24.2295C74.2261 25.0674 75.4184 25.4863 76.8901 25.4863C78.3511 25.4863 79.5327 25.062 80.435 24.2134C81.3481 23.3647 81.8047 22.2046 81.8047 20.7329V18.042C81.8047 16.5918 81.3481 15.4209 80.435 14.5293C79.522 13.627 78.3403 13.1758 76.8901 13.1758C75.4184 13.1758 74.2261 13.6216 73.313 14.5132C72.3999 15.4048 71.9433 16.5811 71.9433 18.042ZM98.081 13.208L89.0737 25.1963H98.1777V28H84.9809V25.4541L93.956 13.4819H84.9487V10.646H98.081V13.208ZM97.9057 19.2827C97.9057 16.479 98.6415 14.2822 100.113 12.6924C101.585 11.1025 103.588 10.3076 106.123 10.3076C108.519 10.3076 110.42 11.0112 111.828 12.4185C113.256 13.8472 113.971 15.7754 113.971 18.2031C113.971 18.7725 113.928 19.3955 113.842 20.0723H101.402V21.0391C101.402 22.4141 101.843 23.5259 102.724 24.3745C103.604 25.2124 104.759 25.6313 106.188 25.6313C107.316 25.6313 108.277 25.3682 109.072 24.8418C109.878 24.3154 110.415 23.6064 110.684 22.7148H114.035C113.691 24.4121 112.8 25.771 111.36 26.7915C109.932 27.812 108.197 28.3223 106.156 28.3223C103.599 28.3223 101.585 27.5112 100.113 25.8892C98.6415 24.2671 97.9057 22.0649 97.9057 19.2827ZM101.402 17.2363V17.6392H110.539V17.0752C110.539 15.8613 110.13 14.8838 109.314 14.1426C108.498 13.3906 107.423 13.0146 106.091 13.0146C104.706 13.0146 103.578 13.4067 102.707 14.1909C101.837 14.9644 101.402 15.9795 101.402 17.2363ZM119.499 28H116.1V10.646H119.064L119.532 13.8687H119.757C120.294 12.7515 121.073 11.8813 122.094 11.2583C123.114 10.6245 124.274 10.3076 125.574 10.3076C127.476 10.3076 128.947 10.9414 129.989 12.209C131.042 13.4766 131.568 15.2114 131.568 17.4136V28H128.136V17.7358C128.136 14.771 126.852 13.2886 124.285 13.2886C122.846 13.2886 121.685 13.8042 120.805 14.8354C119.934 15.8667 119.499 17.2202 119.499 18.896V28ZM138.048 7.81006H134.68V3.71729H138.048V7.81006ZM138.048 28H134.68V10.646H138.048V28ZM149.216 13.4819H145.623V25.2285H149.216V28H145.123C143.211 28 142.255 27.0654 142.255 25.1963V13.4819H139.129V10.646H142.255V5.00635H145.623V10.646H149.216V13.4819ZM149.669 19.2827C149.669 16.479 150.405 14.2822 151.877 12.6924C153.348 11.1025 155.352 10.3076 157.887 10.3076C160.283 10.3076 162.184 11.0112 163.591 12.4185C165.02 13.8472 165.734 15.7754 165.734 18.2031C165.734 18.7725 165.691 19.3955 165.605 20.0723H153.166V21.0391C153.166 22.4141 153.606 23.5259 154.487 24.3745C155.368 25.2124 156.523 25.6313 157.952 25.6313C159.079 25.6313 160.041 25.3682 160.836 24.8418C161.641 24.3154 162.179 23.6064 162.447 22.7148H165.799C165.455 24.4121 164.563 25.771 163.124 26.7915C161.695 27.812 159.96 28.3223 157.919 28.3223C155.363 28.3223 153.348 27.5112 151.877 25.8892C150.405 24.2671 149.669 22.0649 149.669 19.2827ZM153.166 17.2363V17.6392H162.302V17.0752C162.302 15.8613 161.894 14.8838 161.077 14.1426C160.261 13.3906 159.187 13.0146 157.855 13.0146C156.469 13.0146 155.341 13.4067 154.471 14.1909C153.601 14.9644 153.166 15.9795 153.166 17.2363Z"
|
|
75
|
+
fill="#fff"
|
|
76
|
+
/>
|
|
77
|
+
</svg>
|
|
78
|
+
);
|
|
79
|
+
};
|