@rebasepro/studio 0.9.0 → 0.9.1-canary.09aaf62

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.
Files changed (70) hide show
  1. package/README.md +3 -3
  2. package/dist/{ApiExplorer-CdIwR9Ga.js → ApiExplorer-B9M9-uy_.js} +3 -3
  3. package/dist/ApiExplorer-B9M9-uy_.js.map +1 -0
  4. package/dist/{ApiKeysView-D-_FSlNL.js → ApiKeysView-vQKqt2wl.js} +45 -3
  5. package/dist/ApiKeysView-vQKqt2wl.js.map +1 -0
  6. package/dist/{AuthSimulationSelector-iEZ-Or_1.js → AuthSimulationSelector-Bougd521.js} +2 -2
  7. package/dist/AuthSimulationSelector-Bougd521.js.map +1 -0
  8. package/dist/BackupsView-DNS6LdVg.js +227 -0
  9. package/dist/BackupsView-DNS6LdVg.js.map +1 -0
  10. package/dist/{BranchesView-Dlg78EQ8.js → BranchesView-DH0qnU9J.js} +2 -2
  11. package/dist/BranchesView-DH0qnU9J.js.map +1 -0
  12. package/dist/{CronJobsView-4gdtJvoe.js → CronJobsView-B59i3Mis.js} +2 -2
  13. package/dist/CronJobsView-B59i3Mis.js.map +1 -0
  14. package/dist/{JSEditor-Sgmw1SHC.js → JSEditor-BeHHuxhA.js} +5 -5
  15. package/dist/JSEditor-BeHHuxhA.js.map +1 -0
  16. package/dist/LogsExplorer-BCXoGREr.js +298 -0
  17. package/dist/LogsExplorer-BCXoGREr.js.map +1 -0
  18. package/dist/{MonacoEditor-COZqrIJ1.js → MonacoEditor-D0_QljcX.js} +2 -2
  19. package/dist/MonacoEditor-D0_QljcX.js.map +1 -0
  20. package/dist/{RLSEditor-DPhky8XW.js → RLSEditor-D6adwB6e.js} +34 -20
  21. package/dist/RLSEditor-D6adwB6e.js.map +1 -0
  22. package/dist/{SQLEditor-CgR2hlUI.js → SQLEditor-_dCqVAN_.js} +5 -5
  23. package/dist/SQLEditor-_dCqVAN_.js.map +1 -0
  24. package/dist/{SchemaVisualizer-WK4ZZR5X.js → SchemaVisualizer-C_ErehfH.js} +3 -3
  25. package/dist/SchemaVisualizer-C_ErehfH.js.map +1 -0
  26. package/dist/{StorageView-BMhD29YO.js → StorageView-UvyM2xdW.js} +2 -2
  27. package/dist/StorageView-UvyM2xdW.js.map +1 -0
  28. package/dist/components/AuthSimulationSelector.d.ts +1 -1
  29. package/dist/components/Backups/BackupsView.d.ts +2 -0
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.es.js +73 -110
  32. package/dist/index.es.js.map +1 -1
  33. package/package.json +11 -12
  34. package/src/components/ApiExplorer/ApiExplorer.tsx +1 -1
  35. package/src/components/ApiExplorer/TryItPanel.tsx +1 -1
  36. package/src/components/ApiKeys/ApiKeysView.tsx +43 -3
  37. package/src/components/AuthSimulationSelector.tsx +1 -1
  38. package/src/components/Backups/BackupsView.tsx +185 -0
  39. package/src/components/Branches/BranchesView.tsx +1 -1
  40. package/src/components/CronJobs/CronJobsView.tsx +1 -1
  41. package/src/components/JSEditor/JSEditor.tsx +6 -6
  42. package/src/components/JSEditor/JSMonacoEditor.tsx +1 -1
  43. package/src/components/LogsExplorer/LogsExplorer.tsx +168 -46
  44. package/src/components/RLSEditor/PolicyEditor.tsx +5 -3
  45. package/src/components/RLSEditor/RLSEditor.tsx +50 -20
  46. package/src/components/RebaseStudio.tsx +12 -3
  47. package/src/components/SQLEditor/MonacoEditor.tsx +1 -1
  48. package/src/components/SQLEditor/SQLEditor.tsx +3 -3
  49. package/src/components/SQLEditor/SQLEditorSidebar.tsx +1 -1
  50. package/src/components/SQLEditor/SchemaBrowser.tsx +3 -3
  51. package/src/components/SchemaVisualizer/SchemaVisualizer.tsx +3 -2
  52. package/src/components/SchemaVisualizer/TableNode.tsx +1 -1
  53. package/src/components/StorageView/StorageView.tsx +1 -1
  54. package/src/components/StudioHomePage.tsx +62 -87
  55. package/src/index.ts +3 -3
  56. package/dist/ApiExplorer-CdIwR9Ga.js.map +0 -1
  57. package/dist/ApiKeysView-D-_FSlNL.js.map +0 -1
  58. package/dist/AuthSimulationSelector-iEZ-Or_1.js.map +0 -1
  59. package/dist/BranchesView-Dlg78EQ8.js.map +0 -1
  60. package/dist/CronJobsView-4gdtJvoe.js.map +0 -1
  61. package/dist/JSEditor-Sgmw1SHC.js.map +0 -1
  62. package/dist/LogsExplorer-J4xfsuv3.js +0 -206
  63. package/dist/LogsExplorer-J4xfsuv3.js.map +0 -1
  64. package/dist/MonacoEditor-COZqrIJ1.js.map +0 -1
  65. package/dist/RLSEditor-DPhky8XW.js.map +0 -1
  66. package/dist/SQLEditor-CgR2hlUI.js.map +0 -1
  67. package/dist/SchemaVisualizer-WK4ZZR5X.js.map +0 -1
  68. package/dist/StorageView-BMhD29YO.js.map +0 -1
  69. package/dist/index.umd.js +0 -11477
  70. package/dist/index.umd.js.map +0 -1
@@ -0,0 +1,227 @@
1
+ import { useRebaseClient, useSnackbarController } from "@rebasepro/app";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { Alert, Button, Chip, CircularProgress, DatabaseIcon, DownloadIcon, IconButton, RefreshCwIcon, Typography, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/Backups/BackupsView.tsx
6
+ function formatSize(bytes) {
7
+ if (bytes === void 0 || bytes === null) return "—";
8
+ if (bytes < 1024) return `${bytes} B`;
9
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
10
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
11
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
12
+ }
13
+ function formatDate(iso) {
14
+ if (!iso) return "—";
15
+ const d = new Date(iso);
16
+ if (isNaN(d.getTime())) return "—";
17
+ return d.toLocaleString();
18
+ }
19
+ function BackupsView() {
20
+ const client = useRebaseClient();
21
+ const snackbar = useSnackbarController();
22
+ const [backups, setBackups] = useState([]);
23
+ const [destinationKind, setDestinationKind] = useState("local");
24
+ const [configured, setConfigured] = useState(true);
25
+ const [loading, setLoading] = useState(true);
26
+ const [downloading, setDownloading] = useState(null);
27
+ const clientRef = useRef(client);
28
+ clientRef.current = client;
29
+ const snackbarRef = useRef(snackbar);
30
+ snackbarRef.current = snackbar;
31
+ const load = useCallback(async () => {
32
+ const c = clientRef.current;
33
+ if (!c?.backups) {
34
+ setLoading(false);
35
+ setConfigured(false);
36
+ return;
37
+ }
38
+ try {
39
+ const res = await c.backups.list();
40
+ setBackups(res.backups);
41
+ setDestinationKind(res.destinationKind);
42
+ setConfigured(res.configured);
43
+ } catch (e) {
44
+ snackbarRef.current.open({
45
+ type: "error",
46
+ message: e instanceof Error ? e.message : String(e)
47
+ });
48
+ } finally {
49
+ setLoading(false);
50
+ }
51
+ }, []);
52
+ useEffect(() => {
53
+ load();
54
+ }, [load]);
55
+ const handleDownload = async (backup) => {
56
+ const c = clientRef.current;
57
+ if (!c?.backups) return;
58
+ setDownloading(backup.key);
59
+ try {
60
+ const blob = await c.backups.download(backup.key);
61
+ const url = URL.createObjectURL(blob);
62
+ const a = document.createElement("a");
63
+ a.href = url;
64
+ a.download = backup.name;
65
+ document.body.appendChild(a);
66
+ a.click();
67
+ a.remove();
68
+ URL.revokeObjectURL(url);
69
+ } catch (e) {
70
+ snackbarRef.current.open({
71
+ type: "error",
72
+ message: e instanceof Error ? e.message : String(e)
73
+ });
74
+ } finally {
75
+ setDownloading(null);
76
+ }
77
+ };
78
+ if (!client?.backups) return /* @__PURE__ */ jsxs("div", {
79
+ className: "flex flex-col items-center justify-center h-full gap-4 text-center p-8",
80
+ children: [
81
+ /* @__PURE__ */ jsx(DatabaseIcon, {
82
+ size: iconSize.large,
83
+ className: "text-surface-300 dark:text-surface-600"
84
+ }),
85
+ /* @__PURE__ */ jsx(Typography, {
86
+ variant: "h6",
87
+ color: "secondary",
88
+ children: "Backups Not Available"
89
+ }),
90
+ /* @__PURE__ */ jsx(Typography, {
91
+ variant: "body2",
92
+ color: "disabled",
93
+ className: "max-w-md",
94
+ children: "The backups API is not exposed by this backend."
95
+ })
96
+ ]
97
+ });
98
+ if (loading) return /* @__PURE__ */ jsx("div", {
99
+ className: "flex items-center justify-center h-full",
100
+ children: /* @__PURE__ */ jsx(CircularProgress, {})
101
+ });
102
+ return /* @__PURE__ */ jsxs("div", {
103
+ className: "flex flex-col h-full w-full overflow-hidden bg-white dark:bg-surface-950",
104
+ children: [/* @__PURE__ */ jsxs("div", {
105
+ className: cls("flex items-center justify-between px-5 py-2.5 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]", defaultBorderMixin),
106
+ children: [/* @__PURE__ */ jsxs("div", {
107
+ className: "flex items-center gap-2",
108
+ children: [
109
+ /* @__PURE__ */ jsx(DatabaseIcon, {
110
+ size: iconSize.small,
111
+ className: "text-primary"
112
+ }),
113
+ /* @__PURE__ */ jsx(Typography, {
114
+ variant: "subtitle2",
115
+ className: "font-semibold",
116
+ children: "Backups"
117
+ }),
118
+ /* @__PURE__ */ jsx(Chip, {
119
+ size: "smallest",
120
+ className: "bg-surface-200 dark:bg-surface-700 text-surface-600 dark:text-surface-300",
121
+ children: backups.length
122
+ }),
123
+ /* @__PURE__ */ jsx(Chip, {
124
+ size: "smallest",
125
+ className: "bg-surface-100 dark:bg-surface-800 text-surface-500 dark:text-surface-400 uppercase font-mono text-[10px]",
126
+ children: destinationKind
127
+ })
128
+ ]
129
+ }), /* @__PURE__ */ jsx(IconButton, {
130
+ size: "small",
131
+ onClick: load,
132
+ title: "Refresh",
133
+ children: /* @__PURE__ */ jsx(RefreshCwIcon, { size: iconSize.smallest })
134
+ })]
135
+ }), /* @__PURE__ */ jsx("div", {
136
+ className: "flex-1 overflow-y-auto p-5",
137
+ children: !configured ? /* @__PURE__ */ jsx(Alert, {
138
+ color: "info",
139
+ children: /* @__PURE__ */ jsxs(Typography, {
140
+ variant: "body2",
141
+ className: "text-[13px]",
142
+ children: [
143
+ /* @__PURE__ */ jsx("strong", { children: "Backups are not configured." }),
144
+ " Set",
145
+ /* @__PURE__ */ jsx("code", {
146
+ className: "mx-1 px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-950 font-mono text-[12px]",
147
+ children: "BACKUP_DESTINATION"
148
+ }),
149
+ "(a local path or an ",
150
+ /* @__PURE__ */ jsx("code", {
151
+ className: "font-mono text-[12px]",
152
+ children: "s3://"
153
+ }),
154
+ " / ",
155
+ /* @__PURE__ */ jsx("code", {
156
+ className: "font-mono text-[12px]",
157
+ children: "gs://"
158
+ }),
159
+ " URL) and create backups with",
160
+ /* @__PURE__ */ jsx("code", {
161
+ className: "mx-1 px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-950 font-mono text-[12px]",
162
+ children: "rebase db backup"
163
+ }),
164
+ "or a scheduled cron. See docs/backups.md."
165
+ ]
166
+ })
167
+ }) : backups.length === 0 ? /* @__PURE__ */ jsxs("div", {
168
+ className: "flex flex-col items-center justify-center h-full gap-3 text-center",
169
+ children: [/* @__PURE__ */ jsx(DatabaseIcon, {
170
+ size: iconSize.large,
171
+ className: "text-surface-200 dark:text-surface-700"
172
+ }), /* @__PURE__ */ jsxs(Typography, {
173
+ variant: "body2",
174
+ color: "disabled",
175
+ children: [
176
+ "No backups found yet. Run ",
177
+ /* @__PURE__ */ jsx("code", {
178
+ className: "font-mono text-[12px]",
179
+ children: "rebase db backup"
180
+ }),
181
+ " or wait for the next scheduled run."
182
+ ]
183
+ })]
184
+ }) : /* @__PURE__ */ jsx("div", {
185
+ className: "space-y-2 max-w-3xl",
186
+ children: backups.map((backup) => /* @__PURE__ */ jsxs("div", {
187
+ className: cls("flex items-center gap-3 px-4 py-3 rounded-lg border bg-white dark:bg-surface-900", defaultBorderMixin),
188
+ children: [
189
+ /* @__PURE__ */ jsx(DatabaseIcon, {
190
+ size: iconSize.small,
191
+ className: "text-surface-400 shrink-0"
192
+ }),
193
+ /* @__PURE__ */ jsxs("div", {
194
+ className: "flex-1 min-w-0",
195
+ children: [/* @__PURE__ */ jsx(Typography, {
196
+ variant: "body2",
197
+ className: "truncate font-medium font-mono text-[12px]",
198
+ children: backup.name
199
+ }), /* @__PURE__ */ jsxs(Typography, {
200
+ variant: "caption",
201
+ color: "secondary",
202
+ className: "text-[11px]",
203
+ children: [
204
+ formatDate(backup.createdAt),
205
+ " · ",
206
+ formatSize(backup.sizeBytes)
207
+ ]
208
+ })]
209
+ }),
210
+ /* @__PURE__ */ jsx(Button, {
211
+ size: "small",
212
+ variant: "outlined",
213
+ onClick: () => handleDownload(backup),
214
+ disabled: downloading === backup.key,
215
+ startIcon: downloading === backup.key ? /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" }) : /* @__PURE__ */ jsx(DownloadIcon, { size: iconSize.smallest }),
216
+ children: downloading === backup.key ? "Downloading…" : "Download"
217
+ })
218
+ ]
219
+ }, backup.key))
220
+ })
221
+ })]
222
+ });
223
+ }
224
+ //#endregion
225
+ export { BackupsView };
226
+
227
+ //# sourceMappingURL=BackupsView-DNS6LdVg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackupsView-DNS6LdVg.js","names":[],"sources":["../src/components/Backups/BackupsView.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport {\n Alert,\n Button,\n Chip,\n CircularProgress,\n cls,\n DatabaseIcon,\n defaultBorderMixin,\n DownloadIcon,\n iconSize,\n IconButton,\n RefreshCwIcon,\n Typography\n} from \"@rebasepro/ui\";\nimport { useRebaseClient, useSnackbarController } from \"@rebasepro/app\";\nimport type { BackupInfo, RebaseClient } from \"@rebasepro/types\";\n\nfunction formatSize(bytes: number | undefined): string {\n if (bytes === undefined || bytes === null) return \"—\";\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\nfunction formatDate(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n if (isNaN(d.getTime())) return \"—\";\n return d.toLocaleString();\n}\n\nexport function BackupsView() {\n const client = useRebaseClient<RebaseClient>();\n const snackbar = useSnackbarController();\n\n const [backups, setBackups] = useState<BackupInfo[]>([]);\n const [destinationKind, setDestinationKind] = useState<string>(\"local\");\n const [configured, setConfigured] = useState(true);\n const [loading, setLoading] = useState(true);\n const [downloading, setDownloading] = useState<string | null>(null);\n\n const clientRef = useRef(client);\n clientRef.current = client;\n const snackbarRef = useRef(snackbar);\n snackbarRef.current = snackbar;\n\n const load = useCallback(async () => {\n const c = clientRef.current;\n if (!c?.backups) {\n setLoading(false);\n setConfigured(false);\n return;\n }\n try {\n const res = await c.backups.list();\n setBackups(res.backups);\n setDestinationKind(res.destinationKind);\n setConfigured(res.configured);\n } catch (e: unknown) {\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n load();\n }, [load]);\n\n const handleDownload = async (backup: BackupInfo) => {\n const c = clientRef.current;\n if (!c?.backups) return;\n setDownloading(backup.key);\n try {\n const blob = await c.backups.download(backup.key);\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = backup.name;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n } catch (e: unknown) {\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n } finally {\n setDownloading(null);\n }\n };\n\n // Backups API not available on this client (e.g. non-Postgres backend).\n if (!client?.backups) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full gap-4 text-center p-8\">\n <DatabaseIcon size={iconSize.large} className=\"text-surface-300 dark:text-surface-600\"/>\n <Typography variant=\"h6\" color=\"secondary\">Backups Not Available</Typography>\n <Typography variant=\"body2\" color=\"disabled\" className=\"max-w-md\">\n The backups API is not exposed by this backend.\n </Typography>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <CircularProgress/>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full w-full overflow-hidden bg-white dark:bg-surface-950\">\n {/* Header */}\n <div className={cls(\"flex items-center justify-between px-5 py-2.5 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-2\">\n <DatabaseIcon size={iconSize.small} className=\"text-primary\"/>\n <Typography variant=\"subtitle2\" className=\"font-semibold\">Backups</Typography>\n <Chip size=\"smallest\" className=\"bg-surface-200 dark:bg-surface-700 text-surface-600 dark:text-surface-300\">{backups.length}</Chip>\n <Chip size=\"smallest\" className=\"bg-surface-100 dark:bg-surface-800 text-surface-500 dark:text-surface-400 uppercase font-mono text-[10px]\">{destinationKind}</Chip>\n </div>\n <IconButton size=\"small\" onClick={load} title=\"Refresh\">\n <RefreshCwIcon size={iconSize.smallest}/>\n </IconButton>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-5\">\n {!configured ? (\n <Alert color=\"info\">\n <Typography variant=\"body2\" className=\"text-[13px]\">\n <strong>Backups are not configured.</strong> Set\n <code className=\"mx-1 px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-950 font-mono text-[12px]\">BACKUP_DESTINATION</code>\n (a local path or an <code className=\"font-mono text-[12px]\">s3://</code> / <code className=\"font-mono text-[12px]\">gs://</code> URL) and create backups with\n <code className=\"mx-1 px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-950 font-mono text-[12px]\">rebase db backup</code>\n or a scheduled cron. See docs/backups.md.\n </Typography>\n </Alert>\n ) : backups.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center h-full gap-3 text-center\">\n <DatabaseIcon size={iconSize.large} className=\"text-surface-200 dark:text-surface-700\"/>\n <Typography variant=\"body2\" color=\"disabled\">\n No backups found yet. Run <code className=\"font-mono text-[12px]\">rebase db backup</code> or wait for the next scheduled run.\n </Typography>\n </div>\n ) : (\n <div className=\"space-y-2 max-w-3xl\">\n {backups.map(backup => (\n <div\n key={backup.key}\n className={cls(\"flex items-center gap-3 px-4 py-3 rounded-lg border bg-white dark:bg-surface-900\", defaultBorderMixin)}\n >\n <DatabaseIcon size={iconSize.small} className=\"text-surface-400 shrink-0\"/>\n <div className=\"flex-1 min-w-0\">\n <Typography variant=\"body2\" className=\"truncate font-medium font-mono text-[12px]\">{backup.name}</Typography>\n <Typography variant=\"caption\" color=\"secondary\" className=\"text-[11px]\">\n {formatDate(backup.createdAt)} · {formatSize(backup.sizeBytes)}\n </Typography>\n </div>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => handleDownload(backup)}\n disabled={downloading === backup.key}\n startIcon={downloading === backup.key\n ? <CircularProgress size=\"smallest\"/>\n : <DownloadIcon size={iconSize.smallest}/>}\n >\n {downloading === backup.key ? \"Downloading…\" : \"Download\"}\n </Button>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ConfirmationDialog, useRebaseContext, useSnackbarController } from "@rebasepro/core";
1
+ import { ConfirmationDialog, useRebaseContext, useSnackbarController } from "@rebasepro/app";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
3
  import { Alert, Button, Chip, CircularProgress, CopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, GitBranchIcon, IconButton, PlusIcon, RefreshCwIcon, Select, SelectItem, TextField, Trash2Icon, Typography, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -457,4 +457,4 @@ function StatCard({ label, value, mono }) {
457
457
  //#endregion
458
458
  export { BranchesView };
459
459
 
460
- //# sourceMappingURL=BranchesView-Dlg78EQ8.js.map
460
+ //# sourceMappingURL=BranchesView-DH0qnU9J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BranchesView-DH0qnU9J.js","names":[],"sources":["../src/components/Branches/BranchesView.tsx"],"sourcesContent":["\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport {\n Alert,\n Button,\n Chip,\n CircularProgress,\n cls,\n CopyIcon,\n defaultBorderMixin,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n GitBranchIcon,\n IconButton,\n iconSize,\n Paper,\n PlusIcon,\n RefreshCwIcon,\n Select,\n SelectItem,\n TextField,\n Trash2Icon,\n Typography\n} from \"@rebasepro/ui\";\nimport { useRebaseContext, useSnackbarController, ConfirmationDialog } from \"@rebasepro/app\";\nimport { isBranchAdmin } from \"@rebasepro/types\";\nimport type { BranchInfo } from \"@rebasepro/types\";\n\nfunction formatSize(bytes: number | undefined): string {\n if (bytes === undefined || bytes === null) return \"—\";\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\nfunction formatRelative(date: Date | string | undefined): string {\n if (!date) return \"—\";\n const d = date instanceof Date ? date : new Date(date);\n if (isNaN(d.getTime())) return \"—\";\n const now = Date.now();\n const diff = now - d.getTime();\n if (diff < 60_000) return \"just now\";\n if (diff < 3_600_000) { const m = Math.round(diff / 60_000); return `${m}m ago`; }\n if (diff < 86_400_000) { const h = Math.round(diff / 3_600_000); return `${h}h ago`; }\n if (diff < 604_800_000) { const d2 = Math.round(diff / 86_400_000); return `${d2}d ago`; }\n return d.toLocaleDateString();\n}\n\nexport function BranchesView() {\n const { databaseAdmin } = useRebaseContext();\n const snackbar = useSnackbarController();\n\n const [branches, setBranches] = useState<BranchInfo[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedBranch, setSelectedBranch] = useState<string | null>(null);\n\n // Create dialog\n const [createOpen, setCreateOpen] = useState(false);\n const [newBranchName, setNewBranchName] = useState(\"\");\n const [sourceBranch, setSourceBranch] = useState<string | undefined>(undefined);\n const [creating, setCreating] = useState(false);\n\n // Delete confirm\n const [deleteTarget, setDeleteTarget] = useState<string | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n // Refs\n const snackbarRef = useRef(snackbar);\n snackbarRef.current = snackbar;\n\n const branchAdmin = isBranchAdmin(databaseAdmin) ? databaseAdmin : undefined;\n\n const loadBranches = useCallback(async () => {\n if (!branchAdmin) {\n setLoading(false);\n return;\n }\n try {\n const result = await branchAdmin.listBranches();\n setBranches(result);\n } catch (e: unknown) {\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n } finally {\n setLoading(false);\n }\n }, [branchAdmin]);\n\n useEffect(() => {\n loadBranches();\n }, [loadBranches]);\n\n const handleCreate = async () => {\n if (!branchAdmin || !newBranchName.trim()) return;\n setCreating(true);\n try {\n await branchAdmin.createBranch(newBranchName.trim(), sourceBranch ? { source: sourceBranch } : undefined);\n snackbarRef.current.open({\n type: \"success\",\n message: `Branch \"${newBranchName.trim()}\" created successfully`\n });\n setCreateOpen(false);\n setNewBranchName(\"\");\n setSourceBranch(undefined);\n await loadBranches();\n } catch (e: unknown) {\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n } finally {\n setCreating(false);\n }\n };\n\n const handleDelete = async () => {\n if (!branchAdmin || !deleteTarget) return;\n setDeleting(true);\n try {\n await branchAdmin.deleteBranch(deleteTarget);\n snackbarRef.current.open({\n type: \"success\",\n message: `Branch \"${deleteTarget}\" deleted`\n });\n if (selectedBranch === deleteTarget) setSelectedBranch(null);\n setDeleteTarget(null);\n await loadBranches();\n } catch (e: unknown) {\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n } finally {\n setDeleting(false);\n }\n };\n\n // Not supported\n if (!branchAdmin) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full gap-4 text-center p-8\">\n <GitBranchIcon size={iconSize.large} className=\"text-surface-300 dark:text-surface-600\"/>\n <Typography variant=\"h6\" color=\"secondary\">Database Branching Not Available</Typography>\n <Typography variant=\"body2\" color=\"disabled\" className=\"max-w-md\">\n Branching requires a PostgreSQL backend with an admin connection configured.\n Set <code className=\"text-xs bg-surface-100 dark:bg-surface-950 px-1.5 py-0.5 rounded font-mono\">adminConnectionString</code> in your server configuration.\n </Typography>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <CircularProgress/>\n </div>\n );\n }\n\n const selected = branches.find(b => b.name === selectedBranch);\n\n return (\n <div className=\"flex h-full w-full overflow-hidden bg-white dark:bg-surface-950\">\n {/* ── Branch List ── */}\n <div className={cls(\"flex flex-col w-[340px] min-w-[280px] border-r h-full\", defaultBorderMixin)}>\n <div className={cls(\"flex items-center justify-between px-4 py-2.5 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-2\">\n <GitBranchIcon size={iconSize.small} className=\"text-primary\"/>\n <Typography variant=\"subtitle2\" className=\"font-semibold\">Branches</Typography>\n <Chip size=\"smallest\" className=\"bg-surface-200 dark:bg-surface-700 text-surface-600 dark:text-surface-300\">{branches.length}</Chip>\n </div>\n <div className=\"flex items-center gap-1\">\n <IconButton size=\"small\" onClick={loadBranches} title=\"Refresh\">\n <RefreshCwIcon size={iconSize.smallest}/>\n </IconButton>\n <IconButton size=\"small\" onClick={() => setCreateOpen(true)} title=\"Create branch\" className=\"text-primary\">\n <PlusIcon size={iconSize.smallest}/>\n </IconButton>\n </div>\n </div>\n <div className=\"flex-1 overflow-y-auto p-2 space-y-1\">\n {branches.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center h-full gap-3 text-center px-4\">\n <CopyIcon size={iconSize.small} className=\"text-surface-300 dark:text-surface-600\"/>\n <Typography variant=\"body2\" color=\"disabled\" className=\"text-[13px]\">\n No branches yet. Create one to start working with an isolated database copy.\n </Typography>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => setCreateOpen(true)}\n startIcon={<PlusIcon size={iconSize.smallest}/>}\n >\n Create Branch\n </Button>\n </div>\n ) : (\n branches.map(branch => (\n <div\n key={branch.name}\n onClick={() => setSelectedBranch(branch.name)}\n className={cls(\n \"flex items-center gap-3 px-3 py-2.5 rounded-lg cursor-pointer transition-all\",\n selectedBranch === branch.name\n ? \"bg-primary/10 dark:bg-primary/15 ring-1 ring-primary/30\"\n : \"hover:bg-surface-100 dark:hover:bg-surface-950\"\n )}\n >\n <div className=\"w-2 h-2 rounded-full shrink-0 bg-emerald-500\"/>\n <div className=\"flex-1 min-w-0\">\n <Typography variant=\"body2\" className=\"truncate font-medium text-[13px]\">{branch.name}</Typography>\n <Typography variant=\"caption\" color=\"secondary\" className=\"truncate text-[11px]\">\n from {branch.parentDatabase} · {formatRelative(branch.createdAt)}\n </Typography>\n </div>\n {branch.sizeBytes !== undefined && (\n <Typography variant=\"caption\" color=\"disabled\" className=\"font-mono text-[10px] shrink-0\">\n {formatSize(branch.sizeBytes)}\n </Typography>\n )}\n </div>\n ))\n )}\n </div>\n </div>\n\n {/* ── Detail Panel ── */}\n <div className=\"flex-1 flex flex-col min-w-0 h-full overflow-hidden\">\n {!selected ? (\n <div className=\"flex flex-col items-center justify-center h-full gap-3\">\n <GitBranchIcon size={iconSize.large} className=\"text-surface-200 dark:text-surface-700\"/>\n <Typography variant=\"body2\" color=\"disabled\">\n {branches.length === 0 ? \"Create a branch to get started\" : \"Select a branch to view details\"}\n </Typography>\n </div>\n ) : (\n <>\n {/* Header */}\n <div className={cls(\"flex items-center justify-between px-5 py-3 border-b bg-white dark:bg-surface-950 min-h-[56px]\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"w-2.5 h-2.5 rounded-full bg-emerald-500\"/>\n <div className=\"min-w-0\">\n <Typography variant=\"subtitle1\" className=\"font-semibold truncate\">{selected.name}</Typography>\n <Typography variant=\"caption\" color=\"secondary\" className=\"truncate\">\n Created from <span className=\"font-mono text-[11px]\">{selected.parentDatabase}</span>\n </Typography>\n </div>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <Button\n size=\"small\"\n color=\"error\"\n variant=\"outlined\"\n onClick={() => setDeleteTarget(selected.name)}\n startIcon={<Trash2Icon size={iconSize.smallest}/>}\n >\n Delete\n </Button>\n </div>\n </div>\n\n {/* Info Cards */}\n <div className=\"px-5 py-4 bg-surface-50 dark:bg-surface-900/50\">\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-3\">\n <StatCard label=\"Branch Name\" value={selected.name} mono/>\n <StatCard label=\"Source Database\" value={selected.parentDatabase} mono/>\n <StatCard label=\"Created\" value={formatRelative(selected.createdAt)}/>\n <StatCard label=\"Size\" value={formatSize(selected.sizeBytes)}/>\n </div>\n </div>\n\n {/* Usage Info */}\n <div className=\"flex-1 overflow-y-auto px-5 py-4\">\n <Alert color=\"info\">\n <Typography variant=\"body2\" className=\"text-[13px]\">\n <strong>How to use this branch:</strong> Switch your application&apos;s database connection to\n <code className=\"mx-1 px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-950 font-mono text-[12px]\">{selected.name}</code>\n to work with an isolated copy of your data. Changes made to this branch won&apos;t affect your main database.\n </Typography>\n </Alert>\n <div className=\"mt-4 p-4 rounded-lg border bg-surface-50 dark:bg-surface-900 border-surface-200 dark:border-surface-700\">\n <Typography variant=\"caption\" className=\"text-[10px] uppercase tracking-wider text-surface-400 mb-2 block font-medium\">Connection Details</Typography>\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Typography variant=\"caption\" color=\"secondary\" className=\"w-24 shrink-0 text-[11px]\">Database:</Typography>\n <Typography variant=\"body2\" className=\"font-mono text-[12px]\">{selected.name}</Typography>\n </div>\n <div className=\"flex items-center gap-2\">\n <Typography variant=\"caption\" color=\"secondary\" className=\"w-24 shrink-0 text-[11px]\">Branched from:</Typography>\n <Typography variant=\"body2\" className=\"font-mono text-[12px]\">{selected.parentDatabase}</Typography>\n </div>\n <div className=\"flex items-center gap-2\">\n <Typography variant=\"caption\" color=\"secondary\" className=\"w-24 shrink-0 text-[11px]\">Created at:</Typography>\n <Typography variant=\"body2\" className=\"font-mono text-[12px]\">\n {selected.createdAt instanceof Date\n ? selected.createdAt.toLocaleString()\n : new Date(selected.createdAt).toLocaleString()}\n </Typography>\n </div>\n </div>\n </div>\n </div>\n </>\n )}\n </div>\n\n {/* ── Create Dialog ── */}\n <Dialog open={createOpen} onOpenChange={setCreateOpen}>\n <DialogTitle>Create New Branch</DialogTitle>\n <DialogContent className=\"space-y-4 min-w-[400px]\">\n <Typography variant=\"body2\" color=\"secondary\" className=\"text-[13px]\">\n Create an isolated database copy. The branch will be a full clone of the source database at this point in time.\n </Typography>\n <div>\n <TextField\n label=\"Branch Name\"\n value={newBranchName}\n onChange={(e) => setNewBranchName(e.target.value)}\n placeholder=\"e.g. feature-auth, staging, preview-pr-42\"\n size=\"small\"\n autoFocus\n />\n </div>\n {branches.length > 0 && (\n <div>\n <Select\n label=\"Source Database\"\n value={sourceBranch ?? \"__main__\"}\n onValueChange={(v) => setSourceBranch(v === \"__main__\" ? undefined : v)}\n placeholder=\"Default (main database)\"\n size=\"small\"\n >\n <SelectItem value=\"__main__\">Default (main database)</SelectItem>\n {branches.map(b => (\n <SelectItem key={b.name} value={b.name}>{b.name}</SelectItem>\n ))}\n </Select>\n </div>\n )}\n </DialogContent>\n <DialogActions>\n <Button variant=\"text\" onClick={() => setCreateOpen(false)} disabled={creating}>\n Cancel\n </Button>\n <Button\n color=\"primary\"\n onClick={handleCreate}\n disabled={!newBranchName.trim() || creating}\n startIcon={creating ? <CircularProgress size=\"smallest\"/> : <PlusIcon size={iconSize.smallest}/>}\n >\n {creating ? \"Creating...\" : \"Create Branch\"}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* ── Delete Confirm ── */}\n <ConfirmationDialog\n open={!!deleteTarget}\n onAccept={handleDelete}\n onCancel={() => setDeleteTarget(null)}\n title=\"Delete Branch\"\n body={\n <Typography variant=\"body2\">\n Are you sure you want to permanently delete the branch <strong>{deleteTarget}</strong>?\n This action cannot be undone and all data in this branch will be lost.\n </Typography>\n }\n loading={deleting}\n />\n </div>\n );\n}\n\nfunction StatCard({ label, value, mono }: {\n label: string; value: string; mono?: boolean;\n}) {\n return (\n <div className={cls(\"px-3 py-2 rounded-lg border bg-white dark:bg-surface-900\", defaultBorderMixin)}>\n <Typography variant=\"caption\" color=\"secondary\" className=\"text-[10px] uppercase tracking-wider font-medium\">{label}</Typography>\n <Typography variant=\"body2\" className={cls(\n \"mt-0.5 font-semibold text-[13px] truncate\",\n mono && \"font-mono\"\n )}>{value}</Typography>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { useRebaseClient, useSnackbarController } from "@rebasepro/core";
1
+ import { useRebaseClient, useSnackbarController } from "@rebasepro/app";
2
2
  import { useEffect, useRef, useState } from "react";
3
3
  import { AlertCircleIcon, Button, CalendarIcon, CheckCircleIcon, Chip, CircularProgress, HistoryIcon, IconButton, PauseIcon, PlayIcon, RefreshCwIcon, Typography, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -497,4 +497,4 @@ function LogRow({ log }) {
497
497
  //#endregion
498
498
  export { CronJobsView };
499
499
 
500
- //# sourceMappingURL=CronJobsView-4gdtJvoe.js.map
500
+ //# sourceMappingURL=CronJobsView-B59i3Mis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CronJobsView-B59i3Mis.js","names":[],"sources":["../src/components/CronJobs/CronJobsView.tsx"],"sourcesContent":["\nimport React, { useState, useEffect, useRef } from \"react\";\nimport {\n AlertCircleIcon,\n Button,\n CalendarIcon,\n Card,\n CheckCircleIcon,\n Chip,\n CircularProgress,\n cls,\n defaultBorderMixin,\n HistoryIcon,\n IconButton,\n iconSize,\n Paper,\n PauseIcon,\n PlayIcon,\n RefreshCwIcon,\n Typography\n} from \"@rebasepro/ui\";\nimport { useRebaseClient, useSnackbarController } from \"@rebasepro/app\";\nimport type { CronJobStatus, CronJobLogEntry } from \"@rebasepro/types\";\nimport type { RebaseClient } from \"@rebasepro/types\";\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n}\n\nfunction formatRelative(iso: string | undefined): string {\n if (!iso) return \"—\";\n const d = new Date(iso);\n const now = Date.now();\n const diff = d.getTime() - now;\n const abs = Math.abs(diff);\n if (abs < 60000) return diff > 0 ? \"in <1m\" : \"<1m ago\";\n if (abs < 3600000) { const m = Math.round(abs / 60000); return diff > 0 ? `in ${m}m` : `${m}m ago`; }\n if (abs < 86400000) { const h = Math.round(abs / 3600000); return diff > 0 ? `in ${h}h` : `${h}h ago`; }\n return d.toLocaleString();\n}\n\nconst stateColors: Record<string, string> = {\n idle: \"bg-emerald-500\",\nrunning: \"bg-blue-500\",\nsuccess: \"bg-emerald-500\",\n error: \"bg-red-500\",\ndisabled: \"bg-surface-400\"\n};\n\nexport function CronJobsView() {\n const client = useRebaseClient<RebaseClient>();\n const snackbar = useSnackbarController();\n const [jobs, setJobs] = useState<CronJobStatus[]>([]);\n const [loading, setLoading] = useState(true);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [logs, setLogs] = useState<CronJobLogEntry[]>([]);\n const [logsLoading, setLogsLoading] = useState(false);\n const [triggering, setTriggering] = useState<string | null>(null);\n\n // Refs so effects never re-fire due to identity changes\n const clientRef = useRef(client);\n clientRef.current = client;\n const snackbarRef = useRef(snackbar);\n snackbarRef.current = snackbar;\n\n // ── Fetch jobs on mount + poll every 15s ──\n useEffect(() => {\n let cancelled = false;\n\n async function load() {\n const c = clientRef.current;\n if (!c?.cron) {\n setLoading(false);\n return;\n }\n try {\n const res = await c.cron.listJobs();\n if (!cancelled) setJobs(res.jobs);\n } catch (e: unknown) {\n if (!cancelled) {\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n\n load();\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const scheduleNext = () => {\n if (cancelled) return;\n timeoutId = setTimeout(async () => {\n if (document.visibilityState === \"visible\") {\n await load();\n }\n scheduleNext();\n }, 15_000);\n };\n\n scheduleNext();\n\n const handleVisibility = () => {\n if (document.visibilityState === \"visible\") {\n load();\n }\n };\n document.addEventListener(\"visibilitychange\", handleVisibility);\n\n return () => {\n cancelled = true;\n if (timeoutId) clearTimeout(timeoutId);\n document.removeEventListener(\"visibilitychange\", handleVisibility);\n };\n }, []); // runs once\n\n // ── Fetch logs when selection changes ──\n useEffect(() => {\n if (!selectedId) {\n setLogs([]);\n return;\n }\n let cancelled = false;\n const c = clientRef.current;\n if (!c?.cron) return;\n\n setLogsLoading(true);\n c.cron.getJobLogs(selectedId, { limit: 25 })\n .then(res => { if (!cancelled) setLogs(res.logs); })\n .catch(() => { if (!cancelled) setLogs([]); })\n .finally(() => { if (!cancelled) setLogsLoading(false); });\n\n return () => { cancelled = true; };\n }, [selectedId]);\n\n // ── Imperative helpers (not in any dep array) ──\n async function refreshJobs() {\n const c = clientRef.current;\n if (!c?.cron) return;\n try {\n const res = await c.cron.listJobs();\n setJobs(res.jobs);\n } catch { /* swallow */ }\n }\n\n async function refreshLogs(id: string) {\n const c = clientRef.current;\n if (!c?.cron) return;\n setLogsLoading(true);\n try {\n const res = await c.cron.getJobLogs(id, { limit: 25 });\n setLogs(res.logs);\n } catch { setLogs([]); }\n finally { setLogsLoading(false); }\n }\n\n const handleTrigger = async (id: string) => {\n const c = clientRef.current;\n if (!c?.cron) return;\n setTriggering(id);\n try {\n await c.cron.triggerJob(id);\n snackbarRef.current.open({ type: \"success\",\nmessage: \"Job triggered\" });\n await refreshJobs();\n if (selectedId === id) refreshLogs(id);\n } catch (e: unknown) {\n snackbarRef.current.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n } finally { setTriggering(null); }\n };\n\n const handleToggle = async (id: string, enabled: boolean) => {\n const c = clientRef.current;\n if (!c?.cron) return;\n try {\n await c.cron.toggleJob(id, enabled);\n snackbarRef.current.open({ type: \"success\",\nmessage: enabled ? \"Job enabled\" : \"Job paused\" });\n await refreshJobs();\n } catch (e: unknown) {\n snackbarRef.current.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n };\n\n const selectedJob = jobs.find(j => j.id === selectedId);\n\n if (loading) return <div className=\"flex items-center justify-center h-full\"><CircularProgress/></div>;\n\n if (jobs.length === 0) return (\n <div className=\"flex flex-col items-center justify-center h-full gap-4 text-center p-8\">\n <CalendarIcon size={iconSize.medium} className=\"text-surface-300 dark:text-surface-600\"/>\n <Typography variant=\"h6\" color=\"secondary\">No Cron Jobs Registered</Typography>\n <Typography variant=\"body2\" color=\"disabled\" className=\"max-w-md\">\n Create a file in your <code className=\"text-xs bg-surface-100 dark:bg-surface-950 px-1.5 py-0.5 rounded font-mono\">crons/</code> directory that default-exports a <code className=\"text-xs bg-surface-100 dark:bg-surface-950 px-1.5 py-0.5 rounded font-mono\">CronJobDefinition</code>.\n </Typography>\n </div>\n );\n\n return (\n <div className=\"flex h-full w-full overflow-hidden bg-white dark:bg-surface-950\">\n {/* ── Job List ── */}\n <div className={cls(\"flex flex-col w-[340px] min-w-[280px] border-r h-full\", defaultBorderMixin)}>\n <div className={cls(\"flex items-center justify-between px-4 py-2.5 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-2\">\n <CalendarIcon size={iconSize.smallest} className=\"text-primary\"/>\n <Typography variant=\"subtitle2\" className=\"font-semibold\">Cron Jobs</Typography>\n <Chip size=\"smallest\" className=\"bg-surface-200 dark:bg-surface-700 text-surface-600 dark:text-surface-300\">{jobs.length}</Chip>\n </div>\n <IconButton size=\"small\" onClick={refreshJobs} title=\"Refresh\"><RefreshCwIcon size={iconSize.smallest}/></IconButton>\n </div>\n <div className=\"flex-1 overflow-y-auto p-2 space-y-1\">\n {jobs.map(job => (\n <div\n key={job.id}\n onClick={() => setSelectedId(job.id)}\n className={cls(\n \"flex items-center gap-3 px-3 py-2.5 rounded-lg cursor-pointer transition-all\",\n selectedId === job.id\n ? \"bg-primary/10 dark:bg-primary/15 ring-1 ring-primary/30\"\n : \"hover:bg-surface-100 dark:hover:bg-surface-950\"\n )}\n >\n <div className={cls(\"w-2 h-2 rounded-full shrink-0\", stateColors[job.state] || \"bg-surface-400\")}/>\n <div className=\"flex-1 min-w-0\">\n <Typography variant=\"body2\" className=\"truncate font-medium text-[13px]\">{job.name}</Typography>\n <Typography variant=\"caption\" color=\"secondary\" className=\"truncate text-[11px] font-mono\">{job.schedule}</Typography>\n </div>\n {job.state === \"running\" && <CircularProgress size=\"smallest\"/>}\n </div>\n ))}\n </div>\n </div>\n\n {/* ── Detail Panel ── */}\n <div className=\"flex-1 flex flex-col min-w-0 h-full overflow-hidden\">\n {!selectedJob ? (\n <div className=\"flex items-center justify-center h-full\">\n <Typography variant=\"body2\" color=\"disabled\">Select a cron job to view details</Typography>\n </div>\n ) : (\n <>\n {/* Header */}\n <div className={cls(\"flex items-center justify-between px-5 py-3 border-b bg-white dark:bg-surface-950 min-h-[56px]\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className={cls(\"w-2.5 h-2.5 rounded-full\", stateColors[selectedJob.state])}/>\n <div className=\"min-w-0\">\n <Typography variant=\"subtitle1\" className=\"font-semibold truncate\">{selectedJob.name}</Typography>\n {selectedJob.description && <Typography variant=\"caption\" color=\"secondary\" className=\"truncate\">{selectedJob.description}</Typography>}\n </div>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <IconButton title={selectedJob.enabled ? \"Pause job\" : \"Enable job\"} size=\"small\" onClick={() => handleToggle(selectedJob.id, !selectedJob.enabled)}>\n {selectedJob.enabled ? <PauseIcon size={iconSize.small}/> : <PlayIcon size={iconSize.smallest}/>}\n </IconButton>\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={() => handleTrigger(selectedJob.id)}\n disabled={triggering === selectedJob.id}\n startIcon={triggering === selectedJob.id ? <CircularProgress size=\"smallest\"/> : <PlayIcon size={iconSize.smallest}/>}\n >\n Run Now\n </Button>\n </div>\n </div>\n\n {/* Stats Cards */}\n <div className=\"px-5 py-4 bg-surface-50 dark:bg-surface-900/50\">\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-3\">\n <StatCard label=\"Schedule\" value={selectedJob.schedule} mono/>\n <StatCard label=\"Last Run\" value={formatRelative(selectedJob.lastRunAt)}/>\n <StatCard label=\"Next Run\" value={selectedJob.enabled ? formatRelative(selectedJob.nextRunAt) : \"Paused\"}/>\n <StatCard label=\"Duration\" value={selectedJob.lastDurationMs !== undefined ? formatDuration(selectedJob.lastDurationMs) : \"—\"}/>\n </div>\n <div className=\"grid grid-cols-3 gap-3 mt-3\">\n <StatCard label=\"Status\" value={selectedJob.state.toUpperCase()} chipColor={selectedJob.state === \"error\" ? \"red\" : selectedJob.state === \"disabled\" ? \"gray\" : \"green\"}/>\n <StatCard label=\"Total Runs\" value={String(selectedJob.totalRuns)}/>\n <StatCard label=\"Failures\" value={String(selectedJob.totalFailures)} highlight={selectedJob.totalFailures > 0}/>\n </div>\n {selectedJob.lastError && (\n <div className=\"mt-3 p-3 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800/50\">\n <div className=\"flex items-center gap-2 mb-1\">\n <AlertCircleIcon size={iconSize.smallest} className=\"text-red-500\"/>\n <Typography variant=\"caption\" className=\"font-semibold text-red-700 dark:text-red-400\">Last Error</Typography>\n </div>\n <Typography variant=\"caption\" className=\"font-mono text-red-600 dark:text-red-300 text-[11px] break-all\">{selectedJob.lastError}</Typography>\n </div>\n )}\n </div>\n\n {/* Logs Section */}\n <div className={cls(\"flex items-center justify-between px-5 py-2 border-y bg-white dark:bg-surface-950\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-2\">\n <HistoryIcon size={iconSize.smallest} className=\"text-surface-400\"/>\n <Typography variant=\"subtitle2\" className=\"font-semibold text-[13px]\">Execution History</Typography>\n </div>\n <IconButton size=\"small\" onClick={() => refreshLogs(selectedJob.id)} title=\"Refresh logs\"><RefreshCwIcon size={iconSize.smallest}/></IconButton>\n </div>\n <div className=\"flex-1 overflow-y-auto\">\n {logsLoading ? (\n <div className=\"flex justify-center p-8\"><CircularProgress size=\"small\"/></div>\n ) : logs.length === 0 ? (\n <div className=\"flex items-center justify-center h-32\">\n <Typography variant=\"body2\" color=\"disabled\">No executions yet</Typography>\n </div>\n ) : (\n <div className=\"divide-y divide-surface-100 dark:divide-surface-950\">\n {logs.map((log, idx) => (\n <LogRow key={idx} log={log}/>\n ))}\n </div>\n )}\n </div>\n </>\n )}\n </div>\n </div>\n );\n}\n\nfunction StatCard({ label, value, mono, chipColor, highlight }: {\n label: string; value: string; mono?: boolean; chipColor?: string; highlight?: boolean;\n}) {\n return (\n <div className={cls(\"px-3 py-2 rounded-lg border bg-white dark:bg-surface-900\", defaultBorderMixin)}>\n <Typography variant=\"caption\" color=\"secondary\" className=\"text-[10px] uppercase tracking-wider font-medium\">{label}</Typography>\n <Typography variant=\"body2\" className={cls(\n \"mt-0.5 font-semibold text-[13px]\",\n mono && \"font-mono\",\n highlight && \"text-red-500 dark:text-red-400\",\n chipColor === \"red\" && \"text-red-500\",\n chipColor === \"green\" && \"text-emerald-500\",\n chipColor === \"gray\" && \"text-surface-400\"\n )}>{value}</Typography>\n </div>\n );\n}\n\nfunction LogRow({ log }: { log: CronJobLogEntry }) {\n const [expanded, setExpanded] = useState(false);\n return (\n <div className=\"px-5 py-2.5 hover:bg-surface-50 dark:hover:bg-surface-950/50 transition-colors\">\n <div className=\"flex items-center gap-3 cursor-pointer\" onClick={() => setExpanded(!expanded)}>\n {log.success\n ? <CheckCircleIcon size={iconSize.smallest} className=\"text-emerald-500 shrink-0\"/>\n : <AlertCircleIcon size={iconSize.smallest} className=\"text-red-500 shrink-0\"/>}\n <div className=\"flex-1 min-w-0\">\n <Typography variant=\"caption\" className=\"font-mono text-[11px] text-surface-500\">{new Date(log.startedAt).toLocaleString()}</Typography>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {log.manual && <Chip size=\"smallest\" className=\"bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300\">manual</Chip>}\n <Typography variant=\"caption\" className=\"font-mono text-[11px]\">{formatDuration(log.durationMs)}</Typography>\n <svg className={cls(\"w-3 h-3 transition-transform text-surface-400\", expanded && \"rotate-180\")} fill=\"currentColor\" viewBox=\"0 0 20 20\"><path d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\"/></svg>\n </div>\n </div>\n {expanded && (\n <div className=\"mt-2 ml-6 space-y-2\">\n {log.error && (\n <div className=\"p-2 rounded bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800/50\">\n <Typography variant=\"caption\" className=\"font-mono text-[11px] text-red-600 dark:text-red-300 break-all\">{log.error}</Typography>\n </div>\n )}\n {log.logs.length > 0 && (\n <div className=\"p-2 rounded bg-surface-50 dark:bg-surface-900 border border-surface-200 dark:border-surface-700 max-h-40 overflow-auto\">\n {log.logs.map((line, i) => (\n <div key={i} className=\"font-mono text-[11px] text-surface-600 dark:text-surface-400 leading-relaxed\">{line}</div>\n ))}\n </div>\n )}\n {log.result !== undefined && (\n <div className=\"p-2 rounded bg-surface-50 dark:bg-surface-900 border border-surface-200 dark:border-surface-700\">\n <Typography variant=\"caption\" className=\"text-[10px] uppercase tracking-wider text-surface-400 mb-1 block\">Result</Typography>\n <pre className=\"font-mono text-[11px] text-surface-600 dark:text-surface-400 whitespace-pre-wrap break-all\">{JSON.stringify(log.result, null, 2)}</pre>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as AuthSimulationSelector } from "./AuthSimulationSelector-iEZ-Or_1.js";
2
- import { ErrorView, IconForView, useApiConfig, useModeController, useRebaseClient, useRebaseContext, useSnackbarController, useStudioCollectionRegistry, useStudioSidePanelController, useTranslation } from "@rebasepro/core";
1
+ import { t as AuthSimulationSelector } from "./AuthSimulationSelector-Bougd521.js";
2
+ import { ErrorView, IconForView, useApiConfig, useModeController, useRebaseClient, useRebaseContext, useSnackbarController, useStudioCollectionRegistry, useStudioSidePanelController, useTranslation } from "@rebasepro/app";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { Button, Chip, CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, IconButton, Menu, MenuItem, MoreVerticalIcon, PencilIcon, PlayIcon, PlusIcon, ResizablePanels, SaveIcon, Tab, Tabs, TerminalIcon, TextField, Tooltip, Trash2Icon, Typography, VirtualTable, XIcon, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1153,7 +1153,7 @@ function JSEditor() {
1153
1153
  className: "flex shrink-0 items-center justify-end gap-1.5",
1154
1154
  children: [
1155
1155
  /* @__PURE__ */ jsx(Tooltip, {
1156
- title: "SaveIcon as snippet",
1156
+ title: "Save as snippet",
1157
1157
  children: /* @__PURE__ */ jsx(IconButton, {
1158
1158
  size: "small",
1159
1159
  onClick: () => {
@@ -1518,7 +1518,7 @@ function JSEditor() {
1518
1518
  open: showSaveDialog,
1519
1519
  onOpenChange: setShowSaveDialog,
1520
1520
  children: [
1521
- /* @__PURE__ */ jsx(DialogTitle, { children: "SaveIcon Snippet" }),
1521
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Save Snippet" }),
1522
1522
  /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(TextField, {
1523
1523
  label: "Snippet name",
1524
1524
  value: snippetName,
@@ -1566,4 +1566,4 @@ function JSONHighlight({ value }) {
1566
1566
  //#endregion
1567
1567
  export { JSEditor };
1568
1568
 
1569
- //# sourceMappingURL=JSEditor-Sgmw1SHC.js.map
1569
+ //# sourceMappingURL=JSEditor-BeHHuxhA.js.map