@columenlabs/lumen-ui 0.1.66 → 0.1.68
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.
|
@@ -48,7 +48,17 @@ function EmailForm({ adapter, view, inline, }) {
|
|
|
48
48
|
const [replacing, setReplacing] = useState(!view.current);
|
|
49
49
|
const [result, setResult] = useState(null);
|
|
50
50
|
const [busy, setBusy] = useState(null);
|
|
51
|
-
|
|
51
|
+
const [testTo, setTestTo] = useState(view.me);
|
|
52
|
+
// Each route keeps what was typed for it, so switching back and forth loses nothing.
|
|
53
|
+
const [perRoute, setPerRoute] = useState({});
|
|
54
|
+
// Start over only when the saved settings change, never on a refetch of the same ones.
|
|
55
|
+
const savedKey = `${view.current?.updatedAt ?? ''}|${view.current?.route ?? ''}|${view.current?.url ?? ''}`;
|
|
56
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: reset only when the saved settings change
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
setDraft(blank(view));
|
|
59
|
+
setReplacing(!view.current);
|
|
60
|
+
setPerRoute({});
|
|
61
|
+
}, [savedKey]);
|
|
52
62
|
if (!api)
|
|
53
63
|
return null;
|
|
54
64
|
const route = view.routes.find((r) => r.id === draft.route);
|
|
@@ -58,7 +68,9 @@ function EmailForm({ adapter, view, inline, }) {
|
|
|
58
68
|
const run = async (kind) => {
|
|
59
69
|
setBusy(kind);
|
|
60
70
|
try {
|
|
61
|
-
const check = await (kind === 'check'
|
|
71
|
+
const check = await (kind === 'check'
|
|
72
|
+
? api.check(draft)
|
|
73
|
+
: api.test({ ...draft, testTo: testTo.trim() }));
|
|
62
74
|
setResult({ for: draft, check });
|
|
63
75
|
}
|
|
64
76
|
catch (e) {
|
|
@@ -107,6 +119,7 @@ function EmailForm({ adapter, view, inline, }) {
|
|
|
107
119
|
: 'Test to save' }), changed && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
108
120
|
setDraft(blank(view));
|
|
109
121
|
setReplacing(!view.current);
|
|
122
|
+
setPerRoute({});
|
|
110
123
|
setResult(null);
|
|
111
124
|
}, children: "Revert" })), _jsx(SaveButton, { issues: issues, busy: busy === 'save', disabled: !changed, onSave: save })] }));
|
|
112
125
|
return (_jsxs("div", { className: "flex flex-col", children: [inline ? (_jsx("div", { className: "flex justify-end pb-2", children: badge })) : (_jsx(SettingsActions, { children: badge })), _jsx(Step, { n: 1, title: "Reach the server through", children: _jsx(LumenChoice, { label: "Reach the server through", value: draft.route, options: view.routes.map((r) => ({
|
|
@@ -114,12 +127,23 @@ function EmailForm({ adapter, view, inline, }) {
|
|
|
114
127
|
icon: r.id === 'public' ? GlobeIcon : CableIcon,
|
|
115
128
|
title: (_jsxs("span", { className: "flex w-full items-center gap-2", children: [r.label, r.state && (_jsx("span", { className: "ml-auto font-normal text-gain text-xs", children: r.state }))] })),
|
|
116
129
|
})), onValueChange: (id) => {
|
|
130
|
+
if (id === draft.route)
|
|
131
|
+
return;
|
|
132
|
+
setPerRoute((m) => ({
|
|
133
|
+
...m,
|
|
134
|
+
[draft.route]: { url: draft.url, apiKey: draft.apiKey ?? '', replacing },
|
|
135
|
+
}));
|
|
136
|
+
const kept = perRoute[id];
|
|
117
137
|
const next = view.routes.find((r) => r.id === id);
|
|
118
|
-
|
|
138
|
+
const onSaved = !!view.current && view.current.route === id;
|
|
139
|
+
const url = kept?.url ?? (onSaved ? view.current?.url : undefined) ?? next?.url ?? '';
|
|
140
|
+
// The saved key carries to every route (the same server is often reached either way).
|
|
141
|
+
setReplacing(kept?.replacing ?? !view.current);
|
|
142
|
+
set({ route: id, url, apiKey: kept?.apiKey ?? '' });
|
|
119
143
|
} }) }), _jsxs(Step, { n: 2, title: "Email server", children: [_jsx(Labelled, { id: `${ids}-url`, label: _jsx(InfoLabel, { info: route?.urlInfo, children: "Server address" }), children: _jsx(Input, { id: `${ids}-url`, className: "font-code text-xs", value: draft.url, placeholder: route?.url ?? 'https://api.resend.com', onChange: (e) => set({ url: e.target.value }) }) }), _jsx(Labelled, { id: `${ids}-key`, label: "API key", children: replacing ? (_jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { id: `${ids}-key`, type: "password", autoComplete: "off", className: "font-code text-xs", value: draft.apiKey ?? '', onChange: (e) => set({ apiKey: e.target.value }) }), view.current && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
120
144
|
setReplacing(false);
|
|
121
145
|
set({ apiKey: '' });
|
|
122
|
-
}, children: "Keep" }))] })) : (_jsxs("div", { className: "flex h-9 items-center gap-3 rounded-md border px-3 text-sm", children: [_jsx("span", { className: "font-code text-muted-foreground text-xs", children: view.current?.keyHint }), _jsx("span", { className: "ml-auto text-gain text-xs", children: "sealed" }), _jsx(Button, { size: "xs", variant: "link", onClick: () => setReplacing(true), children: "Replace" })] })) })] }), _jsx(Step, { n: 3, title: "Sent from", children: _jsxs("div", { className: "flex flex-col gap-3 sm:flex-row", children: [_jsx(Labelled, { id: `${ids}-name`, label: "Name", className: "sm:flex-1", children: _jsx(Input, { id: `${ids}-name`, value: draft.fromName, onChange: (e) => set({ fromName: e.target.value }) }) }), _jsx(Labelled, { id: `${ids}-from`, label: "Address", className: "sm:flex-[1.4]", children: _jsx(Input, { id: `${ids}-from`, type: "email", value: draft.from, placeholder: "hello@example.com", onChange: (e) => set({ from: e.target.value }) }) })] }) }), _jsxs(Step, { n: 4, title: "Test it", children: [
|
|
146
|
+
}, children: "Keep" }))] })) : (_jsxs("div", { className: "flex h-9 items-center gap-3 rounded-md border px-3 text-sm", children: [_jsx("span", { className: "font-code text-muted-foreground text-xs", children: view.current?.keyHint }), _jsx("span", { className: "ml-auto text-gain text-xs", children: "sealed" }), _jsx(Button, { size: "xs", variant: "link", onClick: () => setReplacing(true), children: "Replace" })] })) })] }), _jsx(Step, { n: 3, title: "Sent from", children: _jsxs("div", { className: "flex flex-col gap-3 sm:flex-row", children: [_jsx(Labelled, { id: `${ids}-name`, label: "Name", className: "sm:flex-1", children: _jsx(Input, { id: `${ids}-name`, value: draft.fromName, onChange: (e) => set({ fromName: e.target.value }) }) }), _jsx(Labelled, { id: `${ids}-from`, label: "Address", className: "sm:flex-[1.4]", children: _jsx(Input, { id: `${ids}-from`, type: "email", value: draft.from, placeholder: "hello@example.com", onChange: (e) => set({ from: e.target.value }) }) })] }) }), _jsxs(Step, { n: 4, title: "Test it", children: [_jsx("div", { className: "flex flex-wrap gap-2", children: _jsxs(Button, { size: "sm", variant: "outline", disabled: !ready || !!busy, onClick: () => run('check'), children: [busy === 'check' ? _jsx(Spinner, {}) : _jsx(PlugZapIcon, {}), " Check connection"] }) }), _jsx(Labelled, { id: `${ids}-test-to`, label: "Send a test email to", children: _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { id: `${ids}-test-to`, type: "email", className: "text-sm", value: testTo, placeholder: view.me, onChange: (e) => setTestTo(e.target.value) }), _jsxs(Button, { size: "sm", variant: "outline", disabled: !ready || !!busy || !testTo.trim(), onClick: () => run('test'), children: [busy === 'test' ? _jsx(Spinner, {}) : _jsx(MailIcon, {}), " Send test"] })] }) }), result && same(result.for, draft) && _jsx(Steps, { check: result.check }), !result && view.lastTest && (_jsxs("p", { className: "text-muted-foreground text-xs", children: ["Last ", view.lastTest.kind === 'test' ? 'test' : 'check', " ", when(view.lastTest.at), ":", ' ', view.lastTest.ok ? 'passed' : 'failed', "."] }))] }), inline ? (_jsx("div", { className: "border-t pt-3", children: footer })) : (_jsx(SettingsFooter, { children: footer }))] }));
|
|
123
147
|
}
|
|
124
148
|
function Step({ n, title, children }) {
|
|
125
149
|
return (_jsxs("section", { className: "flex gap-4 border-t py-5 first-of-type:border-t-0", "aria-label": title, children: [_jsx("span", { className: "num flex size-6 shrink-0 items-center justify-center rounded-full bg-muted font-semibold text-xs", children: n }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-3", children: [_jsx("h3", { className: "font-medium text-sm", children: title }), children] })] }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.68",
|
|
4
4
|
"description": "Lumen: shared React components (frame, views, widgets, charts, drawers).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@codemirror/lang-javascript": "6.2.5",
|
|
46
46
|
"@codemirror/lang-json": "6.0.2",
|
|
47
47
|
"@codemirror/lang-sql": "6.10.0",
|
|
48
|
-
"@columenlabs/lumen-ui-types": "0.1.
|
|
48
|
+
"@columenlabs/lumen-ui-types": "0.1.68",
|
|
49
49
|
"@dnd-kit/core": "6.3.1",
|
|
50
50
|
"@dnd-kit/sortable": "10.0.0",
|
|
51
51
|
"@dnd-kit/utilities": "3.2.2",
|