@rebasepro/studio 0.19.1 → 0.19.2-canary.g09316f6
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/{ApiExplorer-9iwGvNnt.js → ApiExplorer-CND5O4Z5.js} +11 -11
- package/dist/ApiExplorer-CND5O4Z5.js.map +1 -0
- package/dist/{ApiKeysView-EIvegrUk.js → ApiKeysView-OfJLH2x7.js} +14 -14
- package/dist/ApiKeysView-OfJLH2x7.js.map +1 -0
- package/dist/{AuthSimulationSelector-Bougd521.js → AuthSimulationSelector-BewmhMBw.js} +2 -2
- package/dist/{AuthSimulationSelector-Bougd521.js.map → AuthSimulationSelector-BewmhMBw.js.map} +1 -1
- package/dist/{BackupsView-DVkKzaPR.js → BackupsView-D0ZDqTEn.js} +6 -6
- package/dist/{BackupsView-DVkKzaPR.js.map → BackupsView-D0ZDqTEn.js.map} +1 -1
- package/dist/{BranchesView-Df8hQ8wE.js → BranchesView-D6Sz1a5f.js} +11 -11
- package/dist/BranchesView-D6Sz1a5f.js.map +1 -0
- package/dist/{CronJobsView-CLOGjb-L.js → CronJobsView-JwRjQCde.js} +12 -12
- package/dist/CronJobsView-JwRjQCde.js.map +1 -0
- package/dist/{JSEditor-75FTeu6P.js → JSEditor-qiuwmcvk.js} +21 -21
- package/dist/JSEditor-qiuwmcvk.js.map +1 -0
- package/dist/{LogsExplorer-DI8SVpya.js → LogsExplorer-Xq8K4oo6.js} +3 -3
- package/dist/{LogsExplorer-DI8SVpya.js.map → LogsExplorer-Xq8K4oo6.js.map} +1 -1
- package/dist/{RLSEditor-Sa1D34ny.js → RLSEditor-C958zVWW.js} +34 -34
- package/dist/RLSEditor-C958zVWW.js.map +1 -0
- package/dist/{SQLEditor-BfNA8xM3.js → SQLEditor-sdtoZv5F.js} +37 -37
- package/dist/SQLEditor-sdtoZv5F.js.map +1 -0
- package/dist/{SchemaVisualizer-DTDMYL6o.js → SchemaVisualizer-DtDzIUNy.js} +30 -27
- package/dist/SchemaVisualizer-DtDzIUNy.js.map +1 -0
- package/dist/{StorageView-Ed9Q_VlB.js → StorageView-C52dSZNf.js} +16 -16
- package/dist/StorageView-C52dSZNf.js.map +1 -0
- package/dist/index.es.js +19 -19
- package/dist/index.es.js.map +1 -1
- package/package.json +9 -9
- package/dist/ApiExplorer-9iwGvNnt.js.map +0 -1
- package/dist/ApiKeysView-EIvegrUk.js.map +0 -1
- package/dist/BranchesView-Df8hQ8wE.js.map +0 -1
- package/dist/CronJobsView-CLOGjb-L.js.map +0 -1
- package/dist/JSEditor-75FTeu6P.js.map +0 -1
- package/dist/RLSEditor-Sa1D34ny.js.map +0 -1
- package/dist/SQLEditor-BfNA8xM3.js.map +0 -1
- package/dist/SchemaVisualizer-DTDMYL6o.js.map +0 -1
- package/dist/StorageView-Ed9Q_VlB.js.map +0 -1
|
@@ -221,11 +221,11 @@ function CronJobsView() {
|
|
|
221
221
|
]
|
|
222
222
|
});
|
|
223
223
|
return /* @__PURE__ */ jsxs("div", {
|
|
224
|
-
className: "flex h-full w-full overflow-hidden bg-
|
|
224
|
+
className: "flex h-full w-full overflow-hidden bg-surface-card",
|
|
225
225
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
226
226
|
className: cls("flex flex-col w-[340px] min-w-[280px] border-r h-full", defaultBorderMixin),
|
|
227
227
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
228
|
-
className: cls("flex items-center justify-between px-4 py-2.5 border-b bg-surface-
|
|
228
|
+
className: cls("flex items-center justify-between px-4 py-2.5 border-b bg-surface-sheet min-h-[48px]", defaultBorderMixin),
|
|
229
229
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
230
230
|
className: "flex items-center gap-2",
|
|
231
231
|
children: [
|
|
@@ -240,7 +240,7 @@ function CronJobsView() {
|
|
|
240
240
|
}),
|
|
241
241
|
/* @__PURE__ */ jsx(Chip, {
|
|
242
242
|
size: "smallest",
|
|
243
|
-
className: "bg-surface-
|
|
243
|
+
className: "bg-surface-raised text-surface-600 dark:text-surface-300",
|
|
244
244
|
children: jobs.length
|
|
245
245
|
})
|
|
246
246
|
]
|
|
@@ -254,7 +254,7 @@ function CronJobsView() {
|
|
|
254
254
|
className: "flex-1 overflow-y-auto p-2 space-y-1",
|
|
255
255
|
children: jobs.map((job) => /* @__PURE__ */ jsxs("div", {
|
|
256
256
|
onClick: () => setSelectedId(job.id),
|
|
257
|
-
className: cls("flex items-center gap-3 px-3 py-2.5 rounded-lg cursor-pointer transition-all", selectedId === job.id ? "bg-primary/10 dark:bg-primary/15 ring-1 ring-primary/30" : "hover:bg-surface-
|
|
257
|
+
className: cls("flex items-center gap-3 px-3 py-2.5 rounded-lg cursor-pointer transition-all", selectedId === job.id ? "bg-primary/10 dark:bg-primary/15 ring-1 ring-primary/30" : "hover:bg-surface-hover"),
|
|
258
258
|
children: [
|
|
259
259
|
/* @__PURE__ */ jsx("div", { className: cls("w-2 h-2 rounded-full shrink-0", stateColors[job.state] || "bg-surface-400") }),
|
|
260
260
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -285,7 +285,7 @@ function CronJobsView() {
|
|
|
285
285
|
})
|
|
286
286
|
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
287
287
|
/* @__PURE__ */ jsxs("div", {
|
|
288
|
-
className: cls("flex items-center justify-between px-5 py-3 border-b bg-
|
|
288
|
+
className: cls("flex items-center justify-between px-5 py-3 border-b bg-surface-card min-h-[56px]", defaultBorderMixin),
|
|
289
289
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
290
290
|
className: "flex items-center gap-3 min-w-0",
|
|
291
291
|
children: [/* @__PURE__ */ jsx("div", { className: cls("w-2.5 h-2.5 rounded-full", stateColors[selectedJob.state]) }), /* @__PURE__ */ jsxs("div", {
|
|
@@ -319,7 +319,7 @@ function CronJobsView() {
|
|
|
319
319
|
})]
|
|
320
320
|
}),
|
|
321
321
|
/* @__PURE__ */ jsxs("div", {
|
|
322
|
-
className: "px-5 py-4 bg-surface-
|
|
322
|
+
className: "px-5 py-4 bg-surface-sheet",
|
|
323
323
|
children: [
|
|
324
324
|
/* @__PURE__ */ jsxs("div", {
|
|
325
325
|
className: "grid grid-cols-2 md:grid-cols-4 gap-3",
|
|
@@ -383,7 +383,7 @@ function CronJobsView() {
|
|
|
383
383
|
]
|
|
384
384
|
}),
|
|
385
385
|
/* @__PURE__ */ jsxs("div", {
|
|
386
|
-
className: cls("flex items-center justify-between px-5 py-2 border-y bg-
|
|
386
|
+
className: cls("flex items-center justify-between px-5 py-2 border-y bg-surface-card", defaultBorderMixin),
|
|
387
387
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
388
388
|
className: "flex items-center gap-2",
|
|
389
389
|
children: [/* @__PURE__ */ jsx(HistoryIcon, {
|
|
@@ -424,7 +424,7 @@ function CronJobsView() {
|
|
|
424
424
|
}
|
|
425
425
|
function StatCard({ label, value, mono, chipColor, highlight }) {
|
|
426
426
|
return /* @__PURE__ */ jsxs("div", {
|
|
427
|
-
className: cls("px-3 py-2 rounded-lg border bg-
|
|
427
|
+
className: cls("px-3 py-2 rounded-lg border bg-surface-card", defaultBorderMixin),
|
|
428
428
|
children: [/* @__PURE__ */ jsx(Typography, {
|
|
429
429
|
variant: "caption",
|
|
430
430
|
color: "secondary",
|
|
@@ -440,7 +440,7 @@ function StatCard({ label, value, mono, chipColor, highlight }) {
|
|
|
440
440
|
function LogRow({ log }) {
|
|
441
441
|
const [expanded, setExpanded] = useState(false);
|
|
442
442
|
return /* @__PURE__ */ jsxs("div", {
|
|
443
|
-
className: "px-5 py-2.5 hover:bg-surface-
|
|
443
|
+
className: "px-5 py-2.5 hover:bg-surface-hover transition-colors",
|
|
444
444
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
445
445
|
className: "flex items-center gap-3 cursor-pointer",
|
|
446
446
|
onClick: () => setExpanded(!expanded),
|
|
@@ -494,14 +494,14 @@ function LogRow({ log }) {
|
|
|
494
494
|
})
|
|
495
495
|
}),
|
|
496
496
|
log.logs.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
497
|
-
className: "p-2 rounded bg-surface-
|
|
497
|
+
className: "p-2 rounded bg-surface-sheet border border-hairline-strong max-h-40 overflow-auto",
|
|
498
498
|
children: log.logs.map((line, i) => /* @__PURE__ */ jsx("div", {
|
|
499
499
|
className: "font-mono text-[11px] text-surface-600 dark:text-surface-400 leading-relaxed",
|
|
500
500
|
children: line
|
|
501
501
|
}, i))
|
|
502
502
|
}),
|
|
503
503
|
log.result !== void 0 && /* @__PURE__ */ jsxs("div", {
|
|
504
|
-
className: "p-2 rounded bg-surface-
|
|
504
|
+
className: "p-2 rounded bg-surface-sheet border border-hairline-strong",
|
|
505
505
|
children: [/* @__PURE__ */ jsx(Typography, {
|
|
506
506
|
variant: "caption",
|
|
507
507
|
className: "text-[10px] uppercase tracking-wider text-surface-400 mb-1 block",
|
|
@@ -518,4 +518,4 @@ function LogRow({ log }) {
|
|
|
518
518
|
//#endregion
|
|
519
519
|
export { CronJobsView };
|
|
520
520
|
|
|
521
|
-
//# sourceMappingURL=CronJobsView-
|
|
521
|
+
//# sourceMappingURL=CronJobsView-JwRjQCde.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CronJobsView-JwRjQCde.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, useTranslation } from \"@rebasepro/app\";\nimport type { CronJobStatus, CronJobLogEntry } from \"@rebasepro/types\";\nimport type { RebaseClient } from \"@rebasepro/types\";\n\nimport { classifyLoadFailure, type LoadFailure } from \"../load-failure\";\nimport { LoadFailureView } from \"../load-failure-view\";\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 { t } = useTranslation();\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 /** Why the job listing failed, classified — see `load-failure.ts`. */\n const [failure, setFailure] = useState<LoadFailure | 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) {\n setJobs(res.jobs);\n setFailure(null);\n }\n } catch (e: unknown) {\n // A snackbar over an empty list said \"No Cron Jobs Registered\"\n // about a project whose crons the caller may not read. This\n // view polls every 15s, so the toast is also gone long before\n // anyone looks.\n if (!cancelled) setFailure(classifyLoadFailure(e));\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((e: unknown) => {\n if (cancelled) return;\n // Same reasoning as `refreshLogs`: an empty log list is a claim.\n setLogs([]);\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n })\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 setFailure(null);\n } catch (e: unknown) {\n // Swallowed before, which left the list showing whatever it last\n // held — or nothing — after a failed refresh. \"No cron jobs\" and\n // \"could not read the cron jobs\" are not the same statement, so the\n // reason stays on screen rather than passing through a snackbar.\n setFailure(classifyLoadFailure(e));\n }\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 (e: unknown) {\n // Clearing the list silently reads as \"this job has never run\".\n setLogs([]);\n snackbarRef.current.open({\n type: \"error\",\n message: e instanceof Error ? e.message : String(e)\n });\n }\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 (failure) return (\n <LoadFailureView\n failure={failure}\n title={t(\"studio_cron_read_failed\")}\n deniedTitle={t(\"studio_cron_denied_title\")}\n deniedHint={t(\"studio_cron_denied_hint\")}\n onRetry={refreshJobs}\n />\n );\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\">{t(\"studio_cron_empty_title\")}</Typography>\n <Typography variant=\"body2\" color=\"disabled\" className=\"max-w-md\">\n {t(\"studio_cron_empty_body\")}\n </Typography>\n <a\n href=\"https://rebase.pro/docs/backend/cron-jobs\"\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-primary text-sm underline\"\n >\n {t(\"studio_read_the_docs\")}\n </a>\n </div>\n );\n\n return (\n <div className=\"flex h-full w-full overflow-hidden bg-surface-card\">\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-sheet 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\">{t(\"studio_tool_cron\")}</Typography>\n <Chip size=\"smallest\" className=\"bg-surface-raised 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-hover\"\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-surface-card 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-sheet\">\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-surface-card\", 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-surface-card\", 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-hover 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-sheet border border-hairline-strong 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-sheet border border-hairline-strong\">\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,4 +1,4 @@
|
|
|
1
|
-
import { t as AuthSimulationSelector } from "./AuthSimulationSelector-
|
|
1
|
+
import { t as AuthSimulationSelector } from "./AuthSimulationSelector-BewmhMBw.js";
|
|
2
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";
|
|
@@ -378,12 +378,12 @@ var QUICK_REFERENCE = [
|
|
|
378
378
|
var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDeleteSnippet, onInsertCode }) => {
|
|
379
379
|
const [activeTab, setActiveTab] = useState("collections");
|
|
380
380
|
return /* @__PURE__ */ jsxs("div", {
|
|
381
|
-
className: cls("flex flex-col h-full w-full bg-
|
|
381
|
+
className: cls("flex flex-col h-full w-full bg-surface-card border-r", defaultBorderMixin),
|
|
382
382
|
children: [/* @__PURE__ */ jsxs(Tabs, {
|
|
383
383
|
value: activeTab,
|
|
384
384
|
onValueChange: (v) => setActiveTab(v),
|
|
385
385
|
variant: "boxy",
|
|
386
|
-
className: "border-b border-
|
|
386
|
+
className: "border-b border-hairline",
|
|
387
387
|
children: [
|
|
388
388
|
/* @__PURE__ */ jsx(Tab, {
|
|
389
389
|
value: "collections",
|
|
@@ -426,7 +426,7 @@ var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDele
|
|
|
426
426
|
activeTab === "collections" && /* @__PURE__ */ jsxs("div", {
|
|
427
427
|
className: "flex flex-col h-full",
|
|
428
428
|
children: [/* @__PURE__ */ jsx("div", {
|
|
429
|
-
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-
|
|
429
|
+
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-sheet min-h-[48px]", defaultBorderMixin),
|
|
430
430
|
children: /* @__PURE__ */ jsx(Typography, {
|
|
431
431
|
variant: "caption",
|
|
432
432
|
className: "font-semibold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark",
|
|
@@ -450,7 +450,7 @@ var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDele
|
|
|
450
450
|
activeTab === "reference" && /* @__PURE__ */ jsxs("div", {
|
|
451
451
|
className: "flex flex-col h-full",
|
|
452
452
|
children: [/* @__PURE__ */ jsx("div", {
|
|
453
|
-
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-
|
|
453
|
+
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-sheet min-h-[48px]", defaultBorderMixin),
|
|
454
454
|
children: /* @__PURE__ */ jsx(Typography, {
|
|
455
455
|
variant: "caption",
|
|
456
456
|
className: "font-semibold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark",
|
|
@@ -459,7 +459,7 @@ var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDele
|
|
|
459
459
|
}), /* @__PURE__ */ jsx("div", {
|
|
460
460
|
className: "flex-grow overflow-y-auto p-2 space-y-2 no-scrollbar",
|
|
461
461
|
children: QUICK_REFERENCE.map((ref, i) => /* @__PURE__ */ jsxs("div", {
|
|
462
|
-
className: cls("group p-2.5 rounded-lg border hover:border-primary/40 dark:hover:border-primary/40", "bg-
|
|
462
|
+
className: cls("group p-2.5 rounded-lg border hover:border-primary/40 dark:hover:border-primary/40", "bg-surface-card transition-all cursor-pointer", defaultBorderMixin),
|
|
463
463
|
onClick: () => onInsertCode(ref.code),
|
|
464
464
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
465
465
|
className: "flex items-center justify-between mb-1",
|
|
@@ -493,7 +493,7 @@ var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDele
|
|
|
493
493
|
return /* @__PURE__ */ jsxs("div", {
|
|
494
494
|
className: "flex flex-col h-full",
|
|
495
495
|
children: [/* @__PURE__ */ jsx("div", {
|
|
496
|
-
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-
|
|
496
|
+
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-sheet min-h-[48px]", defaultBorderMixin),
|
|
497
497
|
children: /* @__PURE__ */ jsx(Typography, {
|
|
498
498
|
variant: "caption",
|
|
499
499
|
className: "font-semibold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark",
|
|
@@ -545,7 +545,7 @@ var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDele
|
|
|
545
545
|
activeTab === "history" && /* @__PURE__ */ jsxs("div", {
|
|
546
546
|
className: "flex flex-col h-full",
|
|
547
547
|
children: [/* @__PURE__ */ jsx("div", {
|
|
548
|
-
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-
|
|
548
|
+
className: cls("flex items-center justify-between px-3 py-2 border-b bg-surface-sheet min-h-[48px]", defaultBorderMixin),
|
|
549
549
|
children: /* @__PURE__ */ jsx(Typography, {
|
|
550
550
|
variant: "caption",
|
|
551
551
|
className: "font-semibold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark",
|
|
@@ -561,7 +561,7 @@ var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDele
|
|
|
561
561
|
children: "No execution history yet"
|
|
562
562
|
})
|
|
563
563
|
}) : [...history].reverse().map((code, i) => /* @__PURE__ */ jsxs("div", {
|
|
564
|
-
className: "p-2 py-1.5 rounded hover:bg-surface-
|
|
564
|
+
className: "p-2 py-1.5 rounded hover:bg-surface-hover cursor-pointer group transition-colors flex items-start",
|
|
565
565
|
onClick: () => onSelectSnippet(code),
|
|
566
566
|
children: [/* @__PURE__ */ jsx("svg", {
|
|
567
567
|
className: "w-3 h-3 mt-1 mr-2 text-text-disabled dark:text-text-disabled-dark group-hover:text-primary transition-colors flex-shrink-0",
|
|
@@ -589,7 +589,7 @@ var JSEditorSidebar = ({ collections, snippets, history, onSelectSnippet, onDele
|
|
|
589
589
|
function CollectionItem({ collection, onInsertCode }) {
|
|
590
590
|
const [expanded, setExpanded] = useState(false);
|
|
591
591
|
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
592
|
-
className: "flex items-center p-1 cursor-pointer hover:bg-surface-
|
|
592
|
+
className: "flex items-center p-1 cursor-pointer hover:bg-surface-hover rounded transition-colors group relative",
|
|
593
593
|
onClick: () => setExpanded(!expanded),
|
|
594
594
|
children: [
|
|
595
595
|
/* @__PURE__ */ jsx("svg", {
|
|
@@ -631,7 +631,7 @@ function CollectionItem({ collection, onInsertCode }) {
|
|
|
631
631
|
}), expanded && collection.properties.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
632
632
|
className: cls("ml-5 mt-1 space-y-0.5 border-l", defaultBorderMixin),
|
|
633
633
|
children: collection.properties.map((prop) => /* @__PURE__ */ jsxs("div", {
|
|
634
|
-
className: "flex items-center p-1 pl-2 hover:bg-surface-
|
|
634
|
+
className: "flex items-center p-1 pl-2 hover:bg-surface-hover rounded-r cursor-pointer transition-colors group/prop relative min-h-[28px]",
|
|
635
635
|
onClick: () => onInsertCode(`"${prop}"`),
|
|
636
636
|
children: [/* @__PURE__ */ jsx("svg", {
|
|
637
637
|
className: "w-3 h-3 mr-1.5 text-text-disabled dark:text-text-disabled-dark shrink-0",
|
|
@@ -654,7 +654,7 @@ function CollectionItem({ collection, onInsertCode }) {
|
|
|
654
654
|
}
|
|
655
655
|
function SnippetItem({ snippet, onSelect, onDelete }) {
|
|
656
656
|
return /* @__PURE__ */ jsxs("div", {
|
|
657
|
-
className: cls("group p-2 rounded border hover:border-
|
|
657
|
+
className: cls("group p-2 rounded border hover:border-hairline-strong bg-surface-card transition-all cursor-pointer relative", defaultBorderMixin),
|
|
658
658
|
onClick: () => onSelect(snippet.code),
|
|
659
659
|
children: [
|
|
660
660
|
/* @__PURE__ */ jsx(Typography, {
|
|
@@ -1169,7 +1169,7 @@ function JSEditor() {
|
|
|
1169
1169
|
secondPanel: /* @__PURE__ */ jsxs("div", {
|
|
1170
1170
|
className: "flex flex-col h-full overflow-hidden",
|
|
1171
1171
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
1172
|
-
className: cls("flex items-center justify-between pr-2 border-b bg-
|
|
1172
|
+
className: cls("flex items-center justify-between pr-2 border-b bg-surface-card", defaultBorderMixin),
|
|
1173
1173
|
children: [/* @__PURE__ */ jsx("div", {
|
|
1174
1174
|
className: "flex items-center flex-grow overflow-hidden mr-4",
|
|
1175
1175
|
children: /* @__PURE__ */ jsxs("div", {
|
|
@@ -1179,7 +1179,7 @@ function JSEditor() {
|
|
|
1179
1179
|
onValueChange: setActiveTabId,
|
|
1180
1180
|
variant: "boxy",
|
|
1181
1181
|
className: "w-[unset] flex-shrink-0",
|
|
1182
|
-
innerClassName: "bg-
|
|
1182
|
+
innerClassName: "bg-surface-card",
|
|
1183
1183
|
children: tabs.map((tab) => /* @__PURE__ */ jsxs(Tab, {
|
|
1184
1184
|
value: tab.id,
|
|
1185
1185
|
className: "flex items-center justify-between group max-w-[200px]",
|
|
@@ -1258,7 +1258,7 @@ function JSEditor() {
|
|
|
1258
1258
|
firstPanel: /* @__PURE__ */ jsxs("div", {
|
|
1259
1259
|
className: "h-full w-full overflow-hidden flex flex-col",
|
|
1260
1260
|
children: [/* @__PURE__ */ jsx("div", {
|
|
1261
|
-
className: "p-2 px-3 border-b border-
|
|
1261
|
+
className: "p-2 px-3 border-b border-hairline bg-surface-sheet flex items-center shrink-0",
|
|
1262
1262
|
children: /* @__PURE__ */ jsx(AuthSimulationSelector, {
|
|
1263
1263
|
authMode,
|
|
1264
1264
|
setAuthMode,
|
|
@@ -1281,10 +1281,10 @@ function JSEditor() {
|
|
|
1281
1281
|
})]
|
|
1282
1282
|
}),
|
|
1283
1283
|
secondPanel: /* @__PURE__ */ jsxs("div", {
|
|
1284
|
-
className: "h-full w-full flex flex-col bg-surface-
|
|
1284
|
+
className: "h-full w-full flex flex-col bg-surface-well overflow-hidden min-h-0",
|
|
1285
1285
|
children: [
|
|
1286
1286
|
/* @__PURE__ */ jsxs("div", {
|
|
1287
|
-
className: cls("p-2 px-4 bg-surface-
|
|
1287
|
+
className: cls("p-2 px-4 bg-surface-raised border-b shrink-0 flex items-center", defaultBorderMixin),
|
|
1288
1288
|
children: [/* @__PURE__ */ jsx(Typography, {
|
|
1289
1289
|
variant: "caption",
|
|
1290
1290
|
className: "font-semibold text-text-disabled dark:text-text-disabled-dark uppercase tracking-widest text-[10px]",
|
|
@@ -1356,7 +1356,7 @@ function JSEditor() {
|
|
|
1356
1356
|
children: [
|
|
1357
1357
|
"Write JavaScript and press ",
|
|
1358
1358
|
/* @__PURE__ */ jsx("kbd", {
|
|
1359
|
-
className: "px-1.5 py-0.5 rounded bg-surface-
|
|
1359
|
+
className: "px-1.5 py-0.5 rounded bg-surface-raised text-[11px] font-mono",
|
|
1360
1360
|
children: "⌘ Enter"
|
|
1361
1361
|
}),
|
|
1362
1362
|
" to run"
|
|
@@ -1381,7 +1381,7 @@ function JSEditor() {
|
|
|
1381
1381
|
!isRunning && result && !result.error && resultView === "table" && tableData.data.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
1382
1382
|
className: "flex-grow flex flex-col overflow-hidden min-h-0",
|
|
1383
1383
|
children: [matchedCollections.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
1384
|
-
className: cls("px-4 py-1.5 border-b flex items-center gap-2 shrink-0 bg-surface-
|
|
1384
|
+
className: cls("px-4 py-1.5 border-b flex items-center gap-2 shrink-0 bg-surface-sheet", defaultBorderMixin),
|
|
1385
1385
|
children: [/* @__PURE__ */ jsx(Tooltip, {
|
|
1386
1386
|
title: t("studio_sql_admin_collections_tooltip"),
|
|
1387
1387
|
children: /* @__PURE__ */ jsx(Typography, {
|
|
@@ -1520,7 +1520,7 @@ function JSEditor() {
|
|
|
1520
1520
|
]
|
|
1521
1521
|
}),
|
|
1522
1522
|
!isRunning && result && !result.error && resultView === "table" && tableData.data.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
1523
|
-
className: cls("p-2 px-4 border-t bg-surface-
|
|
1523
|
+
className: cls("p-2 px-4 border-t bg-surface-sheet flex justify-between items-center shrink-0", defaultBorderMixin),
|
|
1524
1524
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
1525
1525
|
className: "flex space-x-4",
|
|
1526
1526
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -1627,4 +1627,4 @@ function JSONHighlight({ value }) {
|
|
|
1627
1627
|
//#endregion
|
|
1628
1628
|
export { JSEditor };
|
|
1629
1629
|
|
|
1630
|
-
//# sourceMappingURL=JSEditor-
|
|
1630
|
+
//# sourceMappingURL=JSEditor-qiuwmcvk.js.map
|