@hookbase/cli 1.0.0 → 1.0.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/dist/commands/api-keys.d.ts.map +1 -1
- package/dist/commands/api-keys.js +106 -50
- package/dist/commands/api-keys.js.map +1 -1
- package/dist/commands/applications.d.ts +27 -0
- package/dist/commands/applications.d.ts.map +1 -0
- package/dist/commands/applications.js +216 -0
- package/dist/commands/applications.js.map +1 -0
- package/dist/commands/cron-groups.d.ts +26 -0
- package/dist/commands/cron-groups.d.ts.map +1 -0
- package/dist/commands/cron-groups.js +282 -0
- package/dist/commands/cron-groups.js.map +1 -0
- package/dist/commands/cron.d.ts +60 -0
- package/dist/commands/cron.d.ts.map +1 -0
- package/dist/commands/cron.js +953 -0
- package/dist/commands/cron.js.map +1 -0
- package/dist/commands/deliveries.d.ts.map +1 -1
- package/dist/commands/deliveries.js +36 -29
- package/dist/commands/deliveries.js.map +1 -1
- package/dist/commands/destinations.d.ts.map +1 -1
- package/dist/commands/destinations.js +82 -52
- package/dist/commands/destinations.js.map +1 -1
- package/dist/commands/endpoints.d.ts +39 -0
- package/dist/commands/endpoints.d.ts.map +1 -0
- package/dist/commands/endpoints.js +349 -0
- package/dist/commands/endpoints.js.map +1 -0
- package/dist/commands/events.d.ts.map +1 -1
- package/dist/commands/events.js +15 -14
- package/dist/commands/events.js.map +1 -1
- package/dist/commands/groups/inbound.d.ts +8 -0
- package/dist/commands/groups/inbound.d.ts.map +1 -0
- package/dist/commands/groups/inbound.js +226 -0
- package/dist/commands/groups/inbound.js.map +1 -0
- package/dist/commands/groups/outbound.d.ts +8 -0
- package/dist/commands/groups/outbound.d.ts.map +1 -0
- package/dist/commands/groups/outbound.js +228 -0
- package/dist/commands/groups/outbound.js.map +1 -0
- package/dist/commands/groups/tools.d.ts +6 -0
- package/dist/commands/groups/tools.d.ts.map +1 -0
- package/dist/commands/groups/tools.js +243 -0
- package/dist/commands/groups/tools.js.map +1 -0
- package/dist/commands/logs.js +3 -3
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/outbound.d.ts +40 -0
- package/dist/commands/outbound.d.ts.map +1 -0
- package/dist/commands/outbound.js +389 -0
- package/dist/commands/outbound.js.map +1 -0
- package/dist/commands/routes.d.ts.map +1 -1
- package/dist/commands/routes.js +98 -72
- package/dist/commands/routes.js.map +1 -1
- package/dist/commands/send.d.ts +9 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +132 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/sources.d.ts.map +1 -1
- package/dist/commands/sources.js +78 -42
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/tunnels.d.ts.map +1 -1
- package/dist/commands/tunnels.js +76 -40
- package/dist/commands/tunnels.js.map +1 -1
- package/dist/index.js +143 -309
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +368 -5
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +308 -14
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/config.d.ts +9 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +22 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +32 -15
- package/dist/lib/logger.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +397 -47
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Dashboard.js +1 -1
- package/dist/tui/Dashboard.js.map +1 -1
- package/dist/tui/views/Analytics.d.ts.map +1 -1
- package/dist/tui/views/Analytics.js +11 -2
- package/dist/tui/views/Analytics.js.map +1 -1
- package/dist/tui/views/ApiKeys.d.ts +10 -0
- package/dist/tui/views/ApiKeys.d.ts.map +1 -0
- package/dist/tui/views/ApiKeys.js +211 -0
- package/dist/tui/views/ApiKeys.js.map +1 -0
- package/dist/tui/views/Cron.d.ts +10 -0
- package/dist/tui/views/Cron.d.ts.map +1 -0
- package/dist/tui/views/Cron.js +312 -0
- package/dist/tui/views/Cron.js.map +1 -0
- package/dist/tui/views/Destinations.d.ts.map +1 -1
- package/dist/tui/views/Destinations.js +38 -19
- package/dist/tui/views/Destinations.js.map +1 -1
- package/dist/tui/views/Events.d.ts.map +1 -1
- package/dist/tui/views/Events.js +22 -4
- package/dist/tui/views/Events.js.map +1 -1
- package/dist/tui/views/Outbound.d.ts +8 -0
- package/dist/tui/views/Outbound.d.ts.map +1 -0
- package/dist/tui/views/Outbound.js +543 -0
- package/dist/tui/views/Outbound.js.map +1 -0
- package/dist/tui/views/Overview.d.ts +4 -0
- package/dist/tui/views/Overview.d.ts.map +1 -1
- package/dist/tui/views/Overview.js +35 -11
- package/dist/tui/views/Overview.js.map +1 -1
- package/dist/tui/views/Routes.d.ts +12 -0
- package/dist/tui/views/Routes.d.ts.map +1 -0
- package/dist/tui/views/Routes.js +220 -0
- package/dist/tui/views/Routes.js.map +1 -0
- package/dist/tui/views/Sources.d.ts.map +1 -1
- package/dist/tui/views/Sources.js +22 -12
- package/dist/tui/views/Sources.js.map +1 -1
- package/dist/tui/views/Tunnels.d.ts.map +1 -1
- package/dist/tui/views/Tunnels.js +72 -13
- package/dist/tui/views/Tunnels.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useRef } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import TextInput from 'ink-text-input';
|
|
5
|
+
import SelectInput from 'ink-select-input';
|
|
6
|
+
import Spinner from 'ink-spinner';
|
|
7
|
+
import * as api from '../../lib/api.js';
|
|
8
|
+
function CreateApplication({ onBack, onCreated }) {
|
|
9
|
+
const [step, setStep] = useState('name');
|
|
10
|
+
const [name, setName] = useState('');
|
|
11
|
+
const [description, setDescription] = useState('');
|
|
12
|
+
const [error, setError] = useState(null);
|
|
13
|
+
const [createdApp, setCreatedApp] = useState(null);
|
|
14
|
+
useInput((input, key) => {
|
|
15
|
+
if (key.escape && step !== 'creating') {
|
|
16
|
+
onBack();
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const handleCreate = async () => {
|
|
20
|
+
setStep('creating');
|
|
21
|
+
try {
|
|
22
|
+
const result = await api.createWebhookApplication({
|
|
23
|
+
name: name.trim(),
|
|
24
|
+
description: description.trim() || undefined,
|
|
25
|
+
});
|
|
26
|
+
if (result.error) {
|
|
27
|
+
setError(result.error);
|
|
28
|
+
setStep('name');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
setCreatedApp(result.data?.data || result.data?.application || null);
|
|
32
|
+
setStep('done');
|
|
33
|
+
setTimeout(onCreated, 1500);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
setError(err instanceof Error ? err.message : 'Failed to create');
|
|
38
|
+
setStep('name');
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Create Application" }), _jsx(Text, { dimColor: true, children: " - Esc to cancel" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, children: [step === 'name' && (_jsxs(Box, { children: [_jsx(Text, { children: "Name: " }), _jsx(TextInput, { value: name, onChange: setName, onSubmit: () => name.trim() && setStep('description'), placeholder: "My Webhook App" })] })), step === 'description' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Name: ", name] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Description (optional, Enter to skip): " }), _jsx(TextInput, { value: description, onChange: setDescription, onSubmit: handleCreate, placeholder: "" })] })] })), step === 'creating' && (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " Creating application..." })] })), step === 'done' && createdApp && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", bold: true, children: "Application created!" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "ID: " }), _jsx(Text, { children: createdApp.id })] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "Name: " }), _jsx(Text, { children: createdApp.name })] })] })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }))] })] }));
|
|
42
|
+
}
|
|
43
|
+
function CreateEndpoint({ applications, onBack, onCreated }) {
|
|
44
|
+
const [step, setStep] = useState('app');
|
|
45
|
+
const [selectedAppId, setSelectedAppId] = useState('');
|
|
46
|
+
const [url, setUrl] = useState('');
|
|
47
|
+
const [error, setError] = useState(null);
|
|
48
|
+
const [createdEndpoint, setCreatedEndpoint] = useState(null);
|
|
49
|
+
const [secret, setSecret] = useState(null);
|
|
50
|
+
useInput((input, key) => {
|
|
51
|
+
if (key.escape && step !== 'creating') {
|
|
52
|
+
onBack();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
const appItems = applications.map(a => ({
|
|
56
|
+
label: a.name,
|
|
57
|
+
value: a.id,
|
|
58
|
+
}));
|
|
59
|
+
const handleAppSelect = (item) => {
|
|
60
|
+
setSelectedAppId(item.value);
|
|
61
|
+
setStep('url');
|
|
62
|
+
};
|
|
63
|
+
const handleCreate = async () => {
|
|
64
|
+
if (!url.trim())
|
|
65
|
+
return;
|
|
66
|
+
setStep('creating');
|
|
67
|
+
try {
|
|
68
|
+
const result = await api.createWebhookEndpoint({
|
|
69
|
+
applicationId: selectedAppId,
|
|
70
|
+
url: url.trim(),
|
|
71
|
+
});
|
|
72
|
+
if (result.error) {
|
|
73
|
+
setError(result.error);
|
|
74
|
+
setStep('url');
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const resData = result.data?.data || result.data;
|
|
78
|
+
setCreatedEndpoint(resData || null);
|
|
79
|
+
setSecret(resData?.secret || result.data?.secret || null);
|
|
80
|
+
setStep('done');
|
|
81
|
+
setTimeout(onCreated, 3000);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
setError(err instanceof Error ? err.message : 'Failed to create');
|
|
86
|
+
setStep('url');
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Create Endpoint" }), _jsx(Text, { dimColor: true, children: " - Esc to cancel" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, children: [step === 'app' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Select application:" }), appItems.length === 0 ? (_jsx(Text, { color: "yellow", children: "No applications. Create an application first." })) : (_jsx(SelectInput, { items: appItems, onSelect: handleAppSelect }))] })), step === 'url' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["App: ", applications.find(a => a.id === selectedAppId)?.name] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Endpoint URL: " }), _jsx(TextInput, { value: url, onChange: setUrl, onSubmit: handleCreate, placeholder: "https://api.example.com/webhook" })] })] })), step === 'creating' && (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " Creating endpoint..." })] })), step === 'done' && createdEndpoint && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", bold: true, children: "Endpoint created!" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "ID: " }), _jsx(Text, { children: createdEndpoint.id })] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "URL: " }), _jsx(Text, { color: "blue", children: createdEndpoint.url })] }), secret && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", bold: true, children: "Save this secret - it will not be shown again:" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "cyan", bold: true, children: secret }) })] }))] })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }))] })] }));
|
|
90
|
+
}
|
|
91
|
+
// Helper to get active status from app (API uses isDisabled, not is_active)
|
|
92
|
+
function getAppIsActive(app) {
|
|
93
|
+
if ('isDisabled' in app)
|
|
94
|
+
return !app.isDisabled;
|
|
95
|
+
if ('is_disabled' in app)
|
|
96
|
+
return !app.is_disabled;
|
|
97
|
+
if ('is_active' in app)
|
|
98
|
+
return !!app.is_active;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
function getDate(obj, ...keys) {
|
|
102
|
+
for (const k of keys) {
|
|
103
|
+
if (obj[k])
|
|
104
|
+
return new Date(obj[k]).toLocaleString();
|
|
105
|
+
}
|
|
106
|
+
return '-';
|
|
107
|
+
}
|
|
108
|
+
function AppDetail({ appId, applications, onBack, onRefresh }) {
|
|
109
|
+
const app = applications.find((a) => a.id === appId);
|
|
110
|
+
const [confirmDelete, setConfirmDelete] = useState(false);
|
|
111
|
+
const [deleting, setDeleting] = useState(false);
|
|
112
|
+
const [toggling, setToggling] = useState(false);
|
|
113
|
+
const [message, setMessage] = useState(null);
|
|
114
|
+
const [localActive, setLocalActive] = useState(null);
|
|
115
|
+
const busy = useRef(false);
|
|
116
|
+
const isActive = localActive !== null ? localActive : (app ? getAppIsActive(app) : false);
|
|
117
|
+
useInput(async (input, key) => {
|
|
118
|
+
if (busy.current)
|
|
119
|
+
return;
|
|
120
|
+
if (key.escape || input === 'b') {
|
|
121
|
+
if (confirmDelete) {
|
|
122
|
+
setConfirmDelete(false);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
onBack();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (input === 't' && !confirmDelete && app) {
|
|
129
|
+
busy.current = true;
|
|
130
|
+
setToggling(true);
|
|
131
|
+
const newDisabled = isActive;
|
|
132
|
+
try {
|
|
133
|
+
const result = await api.updateWebhookApplication(appId, { isDisabled: newDisabled });
|
|
134
|
+
if (result.error) {
|
|
135
|
+
setMessage(`Error: ${result.error}`);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
setLocalActive(!newDisabled);
|
|
139
|
+
setMessage(!newDisabled ? 'Application enabled' : 'Application disabled');
|
|
140
|
+
onRefresh();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
setMessage('Failed to toggle');
|
|
145
|
+
}
|
|
146
|
+
setToggling(false);
|
|
147
|
+
setTimeout(() => { busy.current = false; }, 300);
|
|
148
|
+
}
|
|
149
|
+
if (input === 'd' && !confirmDelete) {
|
|
150
|
+
setConfirmDelete(true);
|
|
151
|
+
}
|
|
152
|
+
if (input === 'y' && confirmDelete) {
|
|
153
|
+
busy.current = true;
|
|
154
|
+
setDeleting(true);
|
|
155
|
+
try {
|
|
156
|
+
const result = await api.deleteWebhookApplication(appId);
|
|
157
|
+
if (result.error) {
|
|
158
|
+
setMessage(`Error: ${result.error}`);
|
|
159
|
+
setConfirmDelete(false);
|
|
160
|
+
setTimeout(() => { busy.current = false; }, 300);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
setMessage('Application deleted');
|
|
164
|
+
setTimeout(() => { onRefresh(); onBack(); }, 1500);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
setMessage('Failed to delete');
|
|
169
|
+
setConfirmDelete(false);
|
|
170
|
+
setTimeout(() => { busy.current = false; }, 300);
|
|
171
|
+
}
|
|
172
|
+
setDeleting(false);
|
|
173
|
+
}
|
|
174
|
+
if (input === 'n' && confirmDelete) {
|
|
175
|
+
setConfirmDelete(false);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
if (!app) {
|
|
179
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "Application not found" }), _jsx(Text, { dimColor: true, children: "Press Esc to go back" })] }));
|
|
180
|
+
}
|
|
181
|
+
const a = app;
|
|
182
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Application Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | t: toggle | d: delete" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: app.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Name:" }) }), _jsx(Text, { bold: true, children: app.name })] }), (a.uid || a.externalId) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "UID:" }) }), _jsx(Text, { children: a.uid || a.externalId })] })), (a.description || a.metadata) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Description:" }) }), _jsx(Text, { children: a.description || '-' })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Status:" }) }), _jsx(Text, { color: isActive ? 'green' : 'red', children: isActive ? 'Active' : 'Disabled' })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Endpoints:" }) }), _jsx(Text, { children: a.endpoint_count ?? a.endpointCount ?? 0 })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Messages:" }) }), _jsx(Text, { children: a.message_count ?? a.messageCount ?? 0 })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: getDate(a, 'createdAt', 'created_at') })] }), toggling && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Updating..."] }) })), confirmDelete && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "Delete this application?" }), _jsx(Text, { children: "Press 'y' to confirm, 'n' or Esc to cancel" })] })), deleting && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Deleting..."] }) })), message && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: message.startsWith('Error') ? 'red' : 'green', children: message }) }))] })] }));
|
|
183
|
+
}
|
|
184
|
+
function EndpointDetail({ endpointId, endpoints, onBack, onRefresh }) {
|
|
185
|
+
const endpoint = endpoints.find((e) => e.id === endpointId);
|
|
186
|
+
const [testing, setTesting] = useState(false);
|
|
187
|
+
const [testResult, setTestResult] = useState(null);
|
|
188
|
+
const [confirmDelete, setConfirmDelete] = useState(false);
|
|
189
|
+
const [deleting, setDeleting] = useState(false);
|
|
190
|
+
const [message, setMessage] = useState(null);
|
|
191
|
+
const busy = useRef(false);
|
|
192
|
+
useInput(async (input, key) => {
|
|
193
|
+
if (busy.current)
|
|
194
|
+
return;
|
|
195
|
+
if (key.escape || input === 'b') {
|
|
196
|
+
if (confirmDelete) {
|
|
197
|
+
setConfirmDelete(false);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
onBack();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (input === 't' && !confirmDelete) {
|
|
204
|
+
busy.current = true;
|
|
205
|
+
setTesting(true);
|
|
206
|
+
try {
|
|
207
|
+
const result = await api.testWebhookEndpoint(endpointId);
|
|
208
|
+
if (result.error) {
|
|
209
|
+
setTestResult({ success: false, status: 0, time: 0, error: result.error });
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
const d = result.data?.data || result.data;
|
|
213
|
+
setTestResult({
|
|
214
|
+
success: d?.success === true,
|
|
215
|
+
status: (d?.statusCode ?? d?.status_code ?? 0),
|
|
216
|
+
time: (d?.duration ?? d?.responseTime ?? d?.response_time ?? 0),
|
|
217
|
+
error: d?.error,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
setTestResult({ success: false, status: 0, time: 0, error: 'Test failed' });
|
|
223
|
+
}
|
|
224
|
+
setTesting(false);
|
|
225
|
+
setTimeout(() => { busy.current = false; }, 300);
|
|
226
|
+
}
|
|
227
|
+
if (input === 'd' && !confirmDelete) {
|
|
228
|
+
setConfirmDelete(true);
|
|
229
|
+
}
|
|
230
|
+
if (input === 'y' && confirmDelete) {
|
|
231
|
+
busy.current = true;
|
|
232
|
+
setDeleting(true);
|
|
233
|
+
try {
|
|
234
|
+
const result = await api.deleteWebhookEndpoint(endpointId);
|
|
235
|
+
if (result.error) {
|
|
236
|
+
setMessage(`Error: ${result.error}`);
|
|
237
|
+
setConfirmDelete(false);
|
|
238
|
+
setTimeout(() => { busy.current = false; }, 300);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
setMessage('Endpoint deleted');
|
|
242
|
+
setTimeout(() => { onRefresh(); onBack(); }, 1500);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
setMessage('Failed to delete');
|
|
247
|
+
setConfirmDelete(false);
|
|
248
|
+
}
|
|
249
|
+
setDeleting(false);
|
|
250
|
+
}
|
|
251
|
+
if (input === 'n' && confirmDelete) {
|
|
252
|
+
setConfirmDelete(false);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
if (!endpoint) {
|
|
256
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "Endpoint not found" }), _jsx(Text, { dimColor: true, children: "Press Esc to go back" })] }));
|
|
257
|
+
}
|
|
258
|
+
const ep = endpoint;
|
|
259
|
+
const epActive = ep.is_active || ep.isActive || !ep.isDisabled;
|
|
260
|
+
const eventTypes = Array.isArray(ep.event_types || ep.eventTypes)
|
|
261
|
+
? (ep.event_types || ep.eventTypes).join(', ')
|
|
262
|
+
: '*';
|
|
263
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Endpoint Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | t: test | d: delete" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: endpoint.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "URL:" }) }), _jsx(Text, { color: "blue", children: endpoint.url })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Application:" }) }), _jsx(Text, { children: ep.application_name || ep.applicationName || ep.application_id || ep.applicationId })] }), (ep.description) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Description:" }) }), _jsx(Text, { children: ep.description })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Status:" }) }), _jsx(Text, { color: epActive ? 'green' : 'red', children: epActive ? 'Active' : 'Disabled' })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Circuit:" }) }), (() => {
|
|
264
|
+
const state = ep.circuit_state || ep.circuitState;
|
|
265
|
+
const color = state === 'closed' ? 'green' : state === 'open' ? 'red' : 'yellow';
|
|
266
|
+
return _jsx(Text, { color: color, children: state || 'unknown' });
|
|
267
|
+
})()] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Event Types:" }) }), _jsx(Text, { children: eventTypes })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Timeout:" }) }), _jsxs(Text, { children: [ep.timeout_ms || ep.timeoutMs || 30000, "ms"] })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Messages:" }) }), _jsx(Text, { children: ep.message_count ?? ep.messageCount ?? 0 })] }), (ep.success_rate !== undefined || ep.successRate !== undefined) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Success Rate:" }) }), _jsxs(Text, { children: [((ep.success_rate ?? ep.successRate) * 100).toFixed(1), "%"] })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: getDate(ep, 'createdAt', 'created_at') })] }), testing && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Testing..."] }) })), testResult && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Test Result:" }), testResult.error ? (_jsxs(Text, { color: "red", children: ["Error: ", testResult.error] })) : (_jsxs(Text, { color: testResult.success ? 'green' : 'red', children: [testResult.success ? 'Passed' : 'Failed', " - Status: ", testResult.status > 0 ? testResult.status : 'N/A', " | Time: ", testResult.time, "ms"] }))] })), confirmDelete && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "Delete this endpoint?" }), _jsx(Text, { children: "Press 'y' to confirm, 'n' or Esc to cancel" })] })), deleting && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Deleting..."] }) })), message && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: message.startsWith('Error') ? 'red' : 'green', children: message }) }))] })] }));
|
|
268
|
+
}
|
|
269
|
+
export function OutboundView({ subView, onNavigate, onRefresh }) {
|
|
270
|
+
const [activeSubTab, setActiveSubTab] = useState('apps');
|
|
271
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
272
|
+
const [applications, setApplications] = useState([]);
|
|
273
|
+
const [endpoints, setEndpoints] = useState([]);
|
|
274
|
+
const [messages, setMessages] = useState([]);
|
|
275
|
+
const [dlqMessages, setDlqMessages] = useState([]);
|
|
276
|
+
const [loading, setLoading] = useState(true);
|
|
277
|
+
const [error, setError] = useState(null);
|
|
278
|
+
const [statusMessage, setStatusMessage] = useState(null);
|
|
279
|
+
const SUB_TABS = [
|
|
280
|
+
{ key: 'apps', label: 'Applications' },
|
|
281
|
+
{ key: 'endpoints', label: 'Endpoints' },
|
|
282
|
+
{ key: 'messages', label: 'Messages' },
|
|
283
|
+
{ key: 'dlq', label: 'DLQ' },
|
|
284
|
+
];
|
|
285
|
+
const fetchData = async (isInitial = false) => {
|
|
286
|
+
if (isInitial) {
|
|
287
|
+
setLoading(true);
|
|
288
|
+
}
|
|
289
|
+
setError(null);
|
|
290
|
+
try {
|
|
291
|
+
const [appsRes, endpointsRes, messagesRes, dlqRes] = await Promise.all([
|
|
292
|
+
api.getWebhookApplications(),
|
|
293
|
+
api.getWebhookEndpoints(),
|
|
294
|
+
api.getWebhookMessages({ limit: 50 }),
|
|
295
|
+
api.getDlqMessages({ limit: 50 }),
|
|
296
|
+
]);
|
|
297
|
+
if (appsRes.error)
|
|
298
|
+
throw new Error(appsRes.error);
|
|
299
|
+
if (endpointsRes.error)
|
|
300
|
+
throw new Error(endpointsRes.error);
|
|
301
|
+
// API returns { data: [...] } for all list endpoints
|
|
302
|
+
setApplications(appsRes.data?.data || appsRes.data?.applications || []);
|
|
303
|
+
setEndpoints(endpointsRes.data?.data || endpointsRes.data?.endpoints || []);
|
|
304
|
+
setMessages(messagesRes.data?.data || messagesRes.data?.messages || []);
|
|
305
|
+
setDlqMessages(dlqRes.data?.data || dlqRes.data?.messages || []);
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
setError(err instanceof Error ? err.message : 'Failed to fetch data');
|
|
309
|
+
}
|
|
310
|
+
finally {
|
|
311
|
+
setLoading(false);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
useEffect(() => {
|
|
315
|
+
fetchData(true);
|
|
316
|
+
}, []);
|
|
317
|
+
const getCurrentListLength = () => {
|
|
318
|
+
switch (activeSubTab) {
|
|
319
|
+
case 'apps': return applications.length + 1; // +1 for create item
|
|
320
|
+
case 'endpoints': return endpoints.length + 1; // +1 for create item
|
|
321
|
+
case 'messages': return messages.length;
|
|
322
|
+
case 'dlq': return dlqMessages.length;
|
|
323
|
+
default: return 0;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
const getCurrentDataList = () => {
|
|
327
|
+
switch (activeSubTab) {
|
|
328
|
+
case 'apps': return applications;
|
|
329
|
+
case 'endpoints': return endpoints;
|
|
330
|
+
case 'messages': return messages;
|
|
331
|
+
case 'dlq': return dlqMessages;
|
|
332
|
+
default: return [];
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
useInput((input, key) => {
|
|
336
|
+
if (subView)
|
|
337
|
+
return;
|
|
338
|
+
const listLen = getCurrentListLength();
|
|
339
|
+
// Sub-tab navigation with [ / ] or left/right arrows
|
|
340
|
+
if (input === '[' || input === ']' || key.leftArrow || key.rightArrow) {
|
|
341
|
+
const currentIdx = SUB_TABS.findIndex(t => t.key === activeSubTab);
|
|
342
|
+
const direction = (input === ']' || key.rightArrow) ? 1 : -1;
|
|
343
|
+
const newIdx = (currentIdx + direction + SUB_TABS.length) % SUB_TABS.length;
|
|
344
|
+
setActiveSubTab(SUB_TABS[newIdx].key);
|
|
345
|
+
setSelectedIndex(0);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
// List navigation
|
|
349
|
+
if (key.downArrow || input === 'j') {
|
|
350
|
+
setSelectedIndex(prev => Math.min(prev + 1, listLen - 1));
|
|
351
|
+
}
|
|
352
|
+
if (key.upArrow || input === 'k') {
|
|
353
|
+
setSelectedIndex(prev => Math.max(prev - 1, 0));
|
|
354
|
+
}
|
|
355
|
+
// View details / select create
|
|
356
|
+
if (key.return && listLen > 0) {
|
|
357
|
+
if ((activeSubTab === 'apps' || activeSubTab === 'endpoints') && selectedIndex === 0) {
|
|
358
|
+
onNavigate(activeSubTab === 'apps' ? 'create-app' : 'create-endpoint');
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const dataList = getCurrentDataList();
|
|
362
|
+
const dataIdx = (activeSubTab === 'apps' || activeSubTab === 'endpoints') ? selectedIndex - 1 : selectedIndex;
|
|
363
|
+
if (dataIdx >= 0 && dataIdx < dataList.length) {
|
|
364
|
+
const item = dataList[dataIdx];
|
|
365
|
+
onNavigate(`${activeSubTab}:${item.id}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// Create new
|
|
369
|
+
if (input === 'n') {
|
|
370
|
+
if (activeSubTab === 'apps') {
|
|
371
|
+
onNavigate('create-app');
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (activeSubTab === 'endpoints') {
|
|
375
|
+
onNavigate('create-endpoint');
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Refresh
|
|
380
|
+
if (input === 'r') {
|
|
381
|
+
fetchData();
|
|
382
|
+
}
|
|
383
|
+
// Test endpoint (offset by 1 for create item)
|
|
384
|
+
if (input === 't' && activeSubTab === 'endpoints' && selectedIndex > 0 && endpoints.length > 0) {
|
|
385
|
+
const endpoint = endpoints[selectedIndex - 1];
|
|
386
|
+
if (endpoint)
|
|
387
|
+
testEndpoint(endpoint.id);
|
|
388
|
+
}
|
|
389
|
+
// Retry message/DLQ
|
|
390
|
+
if (input === 'y') {
|
|
391
|
+
if (activeSubTab === 'messages' && messages.length > 0) {
|
|
392
|
+
retryMessage(messages[selectedIndex].id);
|
|
393
|
+
}
|
|
394
|
+
else if (activeSubTab === 'dlq' && dlqMessages.length > 0) {
|
|
395
|
+
retryDlqMessage(dlqMessages[selectedIndex].id);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
const testEndpoint = async (endpointId) => {
|
|
400
|
+
setStatusMessage('Testing endpoint...');
|
|
401
|
+
const result = await api.testWebhookEndpoint(endpointId);
|
|
402
|
+
if (result.error) {
|
|
403
|
+
setStatusMessage(`Test failed: ${result.error}`);
|
|
404
|
+
}
|
|
405
|
+
else if (result.data?.success) {
|
|
406
|
+
const d = result.data?.data || result.data;
|
|
407
|
+
setStatusMessage(`Test passed: ${d.statusCode || d.status_code || '?'} (${d.duration ?? d.responseTime ?? 0}ms)`);
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
setStatusMessage(`Test failed: ${result.data?.error || 'Unknown error'}`);
|
|
411
|
+
}
|
|
412
|
+
setTimeout(() => setStatusMessage(null), 3000);
|
|
413
|
+
};
|
|
414
|
+
const retryMessage = async (messageId) => {
|
|
415
|
+
setStatusMessage('Retrying message...');
|
|
416
|
+
const result = await api.retryWebhookMessage(messageId);
|
|
417
|
+
if (result.error) {
|
|
418
|
+
setStatusMessage(`Retry failed: ${result.error}`);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
setStatusMessage('Message queued for retry');
|
|
422
|
+
fetchData();
|
|
423
|
+
}
|
|
424
|
+
setTimeout(() => setStatusMessage(null), 3000);
|
|
425
|
+
};
|
|
426
|
+
const retryDlqMessage = async (messageId) => {
|
|
427
|
+
setStatusMessage('Retrying DLQ message...');
|
|
428
|
+
const result = await api.retryDlqMessage(messageId);
|
|
429
|
+
if (result.error) {
|
|
430
|
+
setStatusMessage(`Retry failed: ${result.error}`);
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
setStatusMessage('DLQ message queued for retry');
|
|
434
|
+
fetchData();
|
|
435
|
+
}
|
|
436
|
+
setTimeout(() => setStatusMessage(null), 3000);
|
|
437
|
+
};
|
|
438
|
+
const formatStatus = (status) => {
|
|
439
|
+
switch (status) {
|
|
440
|
+
case 'delivered': return _jsx(Text, { color: "green", children: status });
|
|
441
|
+
case 'pending': return _jsx(Text, { color: "yellow", children: status });
|
|
442
|
+
case 'processing': return _jsx(Text, { color: "cyan", children: status });
|
|
443
|
+
case 'failed': return _jsx(Text, { color: "red", children: status });
|
|
444
|
+
case 'exhausted': return _jsx(Text, { color: "red", children: status });
|
|
445
|
+
default: return _jsx(Text, { dimColor: true, children: status });
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
const formatCircuitState = (state) => {
|
|
449
|
+
switch (state) {
|
|
450
|
+
case 'closed': return _jsx(Text, { color: "green", children: "closed" });
|
|
451
|
+
case 'open': return _jsx(Text, { color: "red", children: "open" });
|
|
452
|
+
case 'half_open': return _jsx(Text, { color: "yellow", children: "half_open" });
|
|
453
|
+
default: return _jsx(Text, { dimColor: true, children: "-" });
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
if (loading) {
|
|
457
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " Loading outbound webhooks..." })] }));
|
|
458
|
+
}
|
|
459
|
+
if (error) {
|
|
460
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Press 'r' to retry" })] }));
|
|
461
|
+
}
|
|
462
|
+
// Render create views
|
|
463
|
+
if (subView === 'create-app') {
|
|
464
|
+
return (_jsx(CreateApplication, { onBack: () => onNavigate(null), onCreated: () => { fetchData(); onNavigate(null); } }));
|
|
465
|
+
}
|
|
466
|
+
if (subView === 'create-endpoint') {
|
|
467
|
+
return (_jsx(CreateEndpoint, { applications: applications, onBack: () => onNavigate(null), onCreated: () => { fetchData(); onNavigate(null); } }));
|
|
468
|
+
}
|
|
469
|
+
// Render detail view
|
|
470
|
+
if (subView) {
|
|
471
|
+
const [type, id] = subView.split(':');
|
|
472
|
+
if (type === 'apps') {
|
|
473
|
+
return (_jsx(AppDetail, { appId: id, applications: applications, onBack: () => onNavigate(null), onRefresh: fetchData }));
|
|
474
|
+
}
|
|
475
|
+
if (type === 'endpoints') {
|
|
476
|
+
return (_jsx(EndpointDetail, { endpointId: id, endpoints: endpoints, onBack: () => onNavigate(null), onRefresh: fetchData }));
|
|
477
|
+
}
|
|
478
|
+
if (type === 'messages') {
|
|
479
|
+
const message = messages.find(m => m.id === id);
|
|
480
|
+
if (!message)
|
|
481
|
+
return _jsx(Text, { color: "red", children: "Message not found" });
|
|
482
|
+
const m = message;
|
|
483
|
+
const eventType = m.event_type || m.eventType || '-';
|
|
484
|
+
const respStatus = m.response_status || m.responseStatus;
|
|
485
|
+
const errorMsg = m.error_message || m.errorMessage;
|
|
486
|
+
const nextRetry = m.next_retry_at || m.nextRetryAt;
|
|
487
|
+
const deliveredAt = m.delivered_at || m.deliveredAt;
|
|
488
|
+
const createdAt = m.created_at || m.createdAt || '';
|
|
489
|
+
const endpointId = m.endpoint_id || m.endpointId || '-';
|
|
490
|
+
const appId = m.application_id || m.applicationId || '-';
|
|
491
|
+
const ep = endpoints.find(e => e.id === endpointId);
|
|
492
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Message Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | y: retry" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: message.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Event Type:" }) }), _jsx(Text, { children: eventType })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Endpoint:" }) }), _jsx(Text, { color: "blue", children: ep ? ep.url : endpointId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Application:" }) }), _jsx(Text, { children: appId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Status:" }) }), formatStatus(message.status)] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Attempts:" }) }), _jsxs(Text, { children: [m.attempt_count ?? m.attemptCount ?? 0, "/", m.max_attempts ?? m.maxAttempts ?? 5] })] }), respStatus && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Response:" }) }), _jsx(Text, { color: respStatus >= 200 && respStatus < 300 ? 'green' : 'red', children: respStatus })] })), errorMsg && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Error:" }) }), _jsx(Text, { color: "red", children: errorMsg })] })), nextRetry && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Next Retry:" }) }), _jsx(Text, { color: "yellow", children: new Date(nextRetry).toLocaleString() })] })), deliveredAt && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Delivered:" }) }), _jsx(Text, { color: "green", children: new Date(deliveredAt).toLocaleString() })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: new Date(createdAt).toLocaleString() })] })] })] }));
|
|
493
|
+
}
|
|
494
|
+
if (type === 'dlq') {
|
|
495
|
+
const dlqMessage = dlqMessages.find(m => m.id === id);
|
|
496
|
+
if (!dlqMessage)
|
|
497
|
+
return _jsx(Text, { color: "red", children: "DLQ message not found" });
|
|
498
|
+
const d = dlqMessage;
|
|
499
|
+
const eventType = d.event_type || d.eventType || '-';
|
|
500
|
+
const reason = d.reason || '-';
|
|
501
|
+
const errorMsg = d.error_message || d.errorMessage;
|
|
502
|
+
const lastResp = d.last_response_status || d.lastResponseStatus;
|
|
503
|
+
const origId = d.original_message_id || d.originalMessageId || '-';
|
|
504
|
+
const endpointId = d.endpoint_id || d.endpointId || '-';
|
|
505
|
+
const createdAt = d.created_at || d.createdAt || '';
|
|
506
|
+
const ep = endpoints.find(e => e.id === endpointId);
|
|
507
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "DLQ Message Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | y: retry" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: dlqMessage.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Original Msg:" }) }), _jsx(Text, { dimColor: true, children: origId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Event Type:" }) }), _jsx(Text, { children: eventType })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Endpoint:" }) }), _jsx(Text, { color: "blue", children: ep ? ep.url : endpointId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Reason:" }) }), _jsx(Text, { color: "red", children: reason })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Attempts:" }) }), _jsx(Text, { children: d.attempt_count ?? d.attemptCount ?? 0 })] }), lastResp && (_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Last Response:" }) }), _jsx(Text, { color: "red", children: lastResp })] })), errorMsg && (_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Error:" }) }), _jsx(Text, { color: "red", children: errorMsg })] })), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: new Date(createdAt).toLocaleString() })] })] })] }));
|
|
508
|
+
}
|
|
509
|
+
return _jsx(Text, { color: "red", children: "Unknown view" });
|
|
510
|
+
}
|
|
511
|
+
// Render list view
|
|
512
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [SUB_TABS.map((tab) => (_jsx(Box, { marginRight: 2, children: _jsxs(Text, { bold: activeSubTab === tab.key, color: activeSubTab === tab.key ? 'cyan' : 'gray', children: [activeSubTab === tab.key ? '▸ ' : ' ', tab.label] }) }, tab.key))), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { dimColor: true, children: "[]/\u2190\u2192: switch | \u2191/\u2193: select | Enter: view" })] }), statusMessage && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "yellow", children: statusMessage }) })), activeSubTab === 'apps' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Applications (", applications.length, ")"] }), _jsx(Text, { dimColor: true, children: " | n: new | Enter: details" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: selectedIndex === 0 ? 'cyan' : undefined, bold: selectedIndex === 0, children: selectedIndex === 0 ? '▶' : ' ' }) }), _jsx(Text, { color: "green", children: "+ New Application" })] }), applications.map((app, idx) => {
|
|
513
|
+
const listIdx = idx + 1;
|
|
514
|
+
const isSelected = listIdx === selectedIndex;
|
|
515
|
+
return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 24, children: _jsxs(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: [app.name.slice(0, 22), app.name.length > 22 ? '…' : ''] }) }), _jsx(Box, { width: 14, children: _jsxs(Text, { dimColor: true, children: [app.endpoint_count || 0, " endpoints"] }) }), _jsx(Box, { width: 10, children: _jsxs(Text, { dimColor: true, children: [app.message_count || 0, " msgs"] }) }), _jsx(Box, { width: 8, children: _jsx(Text, { color: getAppIsActive(app) ? 'green' : 'red', children: getAppIsActive(app) ? 'Active' : 'Off' }) })] }, app.id));
|
|
516
|
+
})] })] })), activeSubTab === 'endpoints' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Endpoints (", endpoints.length, ")"] }), _jsx(Text, { dimColor: true, children: " | n: new | t: test | Enter: details" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: selectedIndex === 0 ? 'cyan' : undefined, bold: selectedIndex === 0, children: selectedIndex === 0 ? '▶' : ' ' }) }), _jsx(Text, { color: "green", children: "+ New Endpoint" })] }), endpoints.map((ep, idx) => {
|
|
517
|
+
const listIdx = idx + 1;
|
|
518
|
+
const isSelected = listIdx === selectedIndex;
|
|
519
|
+
return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 46, children: _jsxs(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: [ep.url.slice(0, 44), ep.url.length > 44 ? '…' : ''] }) }), _jsx(Box, { width: 12, children: formatCircuitState(ep.circuitState || ep.circuit_state) }), _jsx(Box, { width: 8, children: _jsx(Text, { color: ep.is_active ? 'green' : 'red', children: ep.is_active ? 'Active' : 'Off' }) })] }, ep.id));
|
|
520
|
+
})] })] })), activeSubTab === 'messages' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Recent Messages (", messages.length, ")"] }), _jsx(Text, { dimColor: true, children: " | Enter: details | y: retry" })] }), messages.length === 0 ? (_jsx(Text, { dimColor: true, children: "No messages. Send events with: hookbase outbound send" })) : (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { borderBottom: true, marginBottom: 0, children: [_jsx(Box, { width: 2, children: _jsx(Text, { children: " " }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Time" }) }), _jsx(Box, { width: 22, children: _jsx(Text, { bold: true, dimColor: true, children: "Event Type" }) }), _jsx(Box, { width: 12, children: _jsx(Text, { bold: true, dimColor: true, children: "Status" }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Response" }) }), _jsx(Box, { width: 12, children: _jsx(Text, { bold: true, dimColor: true, children: "Attempts" }) }), _jsx(Box, { width: 14, children: _jsx(Text, { bold: true, dimColor: true, children: "ID" }) })] }), messages.slice(0, 15).map((msg, idx) => {
|
|
521
|
+
const m = msg;
|
|
522
|
+
const isSelected = idx === selectedIndex;
|
|
523
|
+
const createdAt = m.created_at || m.createdAt || '';
|
|
524
|
+
const d = createdAt ? new Date(createdAt) : null;
|
|
525
|
+
const time = d ? `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}` : '-';
|
|
526
|
+
const eventType = m.event_type || m.eventType || '-';
|
|
527
|
+
const respStatus = m.response_status || m.responseStatus;
|
|
528
|
+
const attempts = `${m.attempt_count ?? m.attemptCount ?? 0}/${m.max_attempts ?? m.maxAttempts ?? 5}`;
|
|
529
|
+
return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: time }) }), _jsx(Box, { width: 22, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, children: eventType.slice(0, 20) }) }), _jsx(Box, { width: 12, children: formatStatus(msg.status) }), _jsx(Box, { width: 10, children: _jsx(Text, { color: respStatus >= 200 && respStatus < 300 ? 'green' : respStatus ? 'red' : 'gray', children: respStatus || '-' }) }), _jsx(Box, { width: 12, children: _jsx(Text, { dimColor: true, children: attempts }) }), _jsxs(Text, { dimColor: true, children: [msg.id.slice(0, 12), "\u2026"] })] }, msg.id));
|
|
530
|
+
})] }))] })), activeSubTab === 'dlq' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Dead Letter Queue (", dlqMessages.length, ")"] }), _jsx(Text, { dimColor: true, children: " | Enter: details | y: retry" })] }), dlqMessages.length === 0 ? (_jsx(Text, { color: "green", children: "No messages in DLQ" })) : (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { borderBottom: true, marginBottom: 0, children: [_jsx(Box, { width: 2, children: _jsx(Text, { children: " " }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Time" }) }), _jsx(Box, { width: 20, children: _jsx(Text, { bold: true, dimColor: true, children: "Event Type" }) }), _jsx(Box, { width: 20, children: _jsx(Text, { bold: true, dimColor: true, children: "Reason" }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Response" }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Attempts" }) }), _jsx(Box, { width: 14, children: _jsx(Text, { bold: true, dimColor: true, children: "ID" }) })] }), dlqMessages.slice(0, 15).map((msg, idx) => {
|
|
531
|
+
const m = msg;
|
|
532
|
+
const isSelected = idx === selectedIndex;
|
|
533
|
+
const createdAt = m.created_at || m.createdAt || '';
|
|
534
|
+
const d = createdAt ? new Date(createdAt) : null;
|
|
535
|
+
const time = d ? `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}` : '-';
|
|
536
|
+
const eventType = m.event_type || m.eventType || '-';
|
|
537
|
+
const reason = m.reason || '-';
|
|
538
|
+
const lastResp = m.last_response_status || m.lastResponseStatus;
|
|
539
|
+
const attempts = m.attempt_count ?? m.attemptCount ?? 0;
|
|
540
|
+
return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: time }) }), _jsx(Box, { width: 20, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, children: eventType.slice(0, 18) }) }), _jsx(Box, { width: 20, children: _jsx(Text, { color: "red", children: reason.slice(0, 18) }) }), _jsx(Box, { width: 10, children: _jsx(Text, { color: lastResp ? 'red' : 'gray', children: lastResp || '-' }) }), _jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: attempts }) }), _jsxs(Text, { dimColor: true, children: [msg.id.slice(0, 12), "\u2026"] })] }, msg.id));
|
|
541
|
+
})] }))] }))] }));
|
|
542
|
+
}
|
|
543
|
+
//# sourceMappingURL=Outbound.js.map
|