@rebasepro/studio 0.0.1-canary.eae7889 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/{ApiExplorer-gMJt5JrS.js → ApiExplorer-DHVmWYfK.js} +13 -13
  2. package/dist/ApiExplorer-DHVmWYfK.js.map +1 -0
  3. package/dist/AuthSimulationSelector-CM488Eei.js +106 -0
  4. package/dist/AuthSimulationSelector-CM488Eei.js.map +1 -0
  5. package/dist/{JSEditor-D8nVp3Lp.js → JSEditor-CSHA0t_O.js} +2 -2
  6. package/dist/{JSEditor-D8nVp3Lp.js.map → JSEditor-CSHA0t_O.js.map} +1 -1
  7. package/dist/{RLSEditor-DBH09u9v.js → RLSEditor-BzDjqo6w.js} +46 -5
  8. package/dist/RLSEditor-BzDjqo6w.js.map +1 -0
  9. package/dist/{SQLEditor-CkVx9vgr.js → SQLEditor-Cr9Kg_Qg.js} +63 -75
  10. package/dist/SQLEditor-Cr9Kg_Qg.js.map +1 -0
  11. package/dist/{SchemaVisualizer-BgD5Zb77.js → SchemaVisualizer-BGpmzyXT.js} +5 -5
  12. package/dist/SchemaVisualizer-BGpmzyXT.js.map +1 -0
  13. package/dist/StorageView-BYoslzBR.js +870 -0
  14. package/dist/StorageView-BYoslzBR.js.map +1 -0
  15. package/dist/core/src/components/BootstrapAdminBanner.d.ts +4 -0
  16. package/dist/core/src/components/LoginView/LoginView.d.ts +22 -0
  17. package/dist/core/src/components/common/useDataTableController.d.ts +3 -3
  18. package/dist/core/src/components/index.d.ts +1 -0
  19. package/dist/core/src/hooks/data/useRelationSelector.d.ts +2 -2
  20. package/dist/core/src/hooks/index.d.ts +1 -0
  21. package/dist/core/src/hooks/useCollapsedGroups.d.ts +16 -1
  22. package/dist/core/src/hooks/useResolvedComponent.d.ts +47 -0
  23. package/dist/index.es.js +79 -71
  24. package/dist/index.es.js.map +1 -1
  25. package/dist/index.umd.js +821 -834
  26. package/dist/index.umd.js.map +1 -1
  27. package/dist/types/src/controllers/auth.d.ts +8 -2
  28. package/dist/types/src/controllers/client.d.ts +13 -0
  29. package/dist/types/src/controllers/collection_registry.d.ts +2 -1
  30. package/dist/types/src/controllers/data_driver.d.ts +36 -1
  31. package/dist/types/src/controllers/navigation.d.ts +18 -6
  32. package/dist/types/src/controllers/registry.d.ts +9 -1
  33. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -0
  34. package/dist/types/src/rebase_context.d.ts +17 -0
  35. package/dist/types/src/types/backend_hooks.d.ts +187 -0
  36. package/dist/types/src/types/collections.d.ts +31 -11
  37. package/dist/types/src/types/component_ref.d.ts +47 -0
  38. package/dist/types/src/types/cron.d.ts +1 -1
  39. package/dist/types/src/types/entity_views.d.ts +6 -7
  40. package/dist/types/src/types/formex.d.ts +40 -0
  41. package/dist/types/src/types/index.d.ts +3 -0
  42. package/dist/types/src/types/plugins.d.ts +6 -3
  43. package/dist/types/src/types/properties.d.ts +72 -88
  44. package/dist/types/src/types/slots.d.ts +20 -10
  45. package/dist/types/src/types/translations.d.ts +6 -0
  46. package/dist/ui/src/components/FileUpload.d.ts +1 -1
  47. package/dist/ui/src/components/SearchBar.d.ts +5 -1
  48. package/dist/ui/src/styles.d.ts +2 -2
  49. package/package.json +10 -10
  50. package/src/components/ApiExplorer/ApiExplorer.tsx +7 -5
  51. package/src/components/ApiExplorer/TryItPanel.tsx +29 -53
  52. package/src/components/AuthSimulationSelector.tsx +13 -17
  53. package/src/components/RLSEditor/RLSEditor.tsx +82 -3
  54. package/src/components/SQLEditor/SQLEditor.tsx +16 -18
  55. package/src/components/SQLEditor/SchemaBrowser.tsx +6 -8
  56. package/src/components/SchemaVisualizer/SchemaVisualizer.tsx +20 -22
  57. package/src/components/StorageView/StorageView.tsx +719 -304
  58. package/src/components/StudioHomePage.tsx +4 -1
  59. package/dist/ApiExplorer-gMJt5JrS.js.map +0 -1
  60. package/dist/AuthSimulationSelector-BF4rkRGp.js +0 -118
  61. package/dist/AuthSimulationSelector-BF4rkRGp.js.map +0 -1
  62. package/dist/RLSEditor-DBH09u9v.js.map +0 -1
  63. package/dist/SQLEditor-CkVx9vgr.js.map +0 -1
  64. package/dist/SchemaVisualizer-BgD5Zb77.js.map +0 -1
  65. package/dist/StorageView-CTqGFhY9.js +0 -907
  66. package/dist/StorageView-CTqGFhY9.js.map +0 -1
package/dist/index.umd.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@rebasepro/core"), require("react/jsx-runtime"), require("react"), require("@rebasepro/ui"), require("react-compiler-runtime"), require("lucide-react"), require("react-router-dom"), require("react-dom"), require("pgsql-ast-parser"), require("@rebasepro/utils"), require("prism-react-renderer"), require("@rebasepro/client"), require("@monaco-editor/react"), require("@rebasepro/types"), require("@xyflow/react"), require("@xyflow/react/dist/style.css"), require("@rebasepro/common"), require("dagre")) : typeof define === "function" && define.amd ? define(["exports", "@rebasepro/core", "react/jsx-runtime", "react", "@rebasepro/ui", "react-compiler-runtime", "lucide-react", "react-router-dom", "react-dom", "pgsql-ast-parser", "@rebasepro/utils", "prism-react-renderer", "@rebasepro/client", "@monaco-editor/react", "@rebasepro/types", "@xyflow/react", "@xyflow/react/dist/style.css", "@rebasepro/common", "dagre"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["Rebase collection editor"] = {}, global.core, global.jsxRuntime, global.React, global.ui, global.reactCompilerRuntime, global.lucideReact, global.reactRouterDom, global.reactDom, global.pgsqlAstParser, global.utils, global.prismReactRenderer, global.client, global.Editor, global.types, global.react, null, global.common, global.dagre));
3
- })(this, (function(exports2, core, jsxRuntime, React, ui, reactCompilerRuntime, lucideReact, reactRouterDom, reactDom, pgsqlAstParser, utils, prismReactRenderer, client, Editor, types, react, style_css, common, dagre) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@rebasepro/core"), require("react/jsx-runtime"), require("react"), require("@rebasepro/ui"), require("react-compiler-runtime"), require("lucide-react"), require("react-router-dom"), require("react-dom"), require("pgsql-ast-parser"), require("@rebasepro/utils"), require("prism-react-renderer"), require("@rebasepro/client"), require("@monaco-editor/react"), require("@rebasepro/types"), require("react-dropzone"), require("@xyflow/react"), require("@xyflow/react/dist/style.css"), require("@rebasepro/common"), require("dagre")) : typeof define === "function" && define.amd ? define(["exports", "@rebasepro/core", "react/jsx-runtime", "react", "@rebasepro/ui", "react-compiler-runtime", "lucide-react", "react-router-dom", "react-dom", "pgsql-ast-parser", "@rebasepro/utils", "prism-react-renderer", "@rebasepro/client", "@monaco-editor/react", "@rebasepro/types", "react-dropzone", "@xyflow/react", "@xyflow/react/dist/style.css", "@rebasepro/common", "dagre"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["Rebase collection editor"] = {}, global.core, global.jsxRuntime, global.React, global.ui, global.reactCompilerRuntime, global.lucideReact, global.reactRouterDom, global.reactDom, global.pgsqlAstParser, global.utils, global.prismReactRenderer, global.client, global.Editor, global.types, global.reactDropzone, global.react, null, global.common, global.dagre));
3
+ })(this, (function(exports2, core, jsxRuntime, React, ui, reactCompilerRuntime, lucideReact, reactRouterDom, reactDom, pgsqlAstParser, utils, prismReactRenderer, client, Editor, types, reactDropzone, react, style_css, common, dagre) {
4
4
  "use strict";
5
5
  const SECTIONS = [{
6
6
  label: "Database",
@@ -84,7 +84,7 @@
84
84
  }]
85
85
  }];
86
86
  function StudioHomePage(t0) {
87
- const $ = reactCompilerRuntime.c(29);
87
+ const $ = reactCompilerRuntime.c(30);
88
88
  const {
89
89
  additionalActions,
90
90
  additionalChildrenStart,
@@ -131,20 +131,27 @@
131
131
  const sectionProps = t3;
132
132
  const pluginActions = core.useSlot("home.actions", sectionProps);
133
133
  let t4;
134
- if ($[6] !== additionalActions || $[7] !== pluginActions) {
135
- t4 = (additionalActions || pluginActions) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full sticky py-4 transition-all duration-400 ease-in-out top-0 z-10 flex flex-row gap-4 justify-end", children: [
134
+ if ($[6] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
135
+ t4 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(core.BootstrapAdminBanner, {}) });
136
+ $[6] = t4;
137
+ } else {
138
+ t4 = $[6];
139
+ }
140
+ let t5;
141
+ if ($[7] !== additionalActions || $[8] !== pluginActions) {
142
+ t5 = (additionalActions || pluginActions) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full sticky py-4 transition-all duration-400 ease-in-out top-0 z-10 flex flex-row gap-4 justify-end", children: [
136
143
  additionalActions,
137
144
  pluginActions
138
145
  ] });
139
- $[6] = additionalActions;
140
- $[7] = pluginActions;
141
- $[8] = t4;
146
+ $[7] = additionalActions;
147
+ $[8] = pluginActions;
148
+ $[9] = t5;
142
149
  } else {
143
- t4 = $[8];
150
+ t5 = $[9];
144
151
  }
145
- let t5;
146
- if ($[9] !== context || $[10] !== navigate) {
147
- t5 = SECTIONS.map((section) => /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": section.label, children: [
152
+ let t6;
153
+ if ($[10] !== context || $[11] !== navigate) {
154
+ t6 = SECTIONS.map((section) => /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": section.label, children: [
148
155
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", component: "h2", color: "secondary", className: "py-2 font-medium uppercase text-sm text-surface-600 dark:text-surface-400", children: section.label }),
149
156
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3 mt-2", children: section.tools.map((tool) => /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { onClick: () => {
150
157
  navigate(tool.path);
@@ -166,43 +173,43 @@
166
173
  }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, { className: "text-primary", size: ui.iconSize.small }) }) })
167
174
  ] }) }, tool.path)) })
168
175
  ] }, section.label));
169
- $[9] = context;
170
- $[10] = navigate;
171
- $[11] = t5;
172
- } else {
173
- t5 = $[11];
174
- }
175
- let t6;
176
- if ($[12] !== t5) {
177
- t6 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-8 pt-2", children: t5 });
178
- $[12] = t5;
179
- $[13] = t6;
176
+ $[10] = context;
177
+ $[11] = navigate;
178
+ $[12] = t6;
180
179
  } else {
181
- t6 = $[13];
180
+ t6 = $[12];
182
181
  }
183
182
  let t7;
184
- if ($[14] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
185
- t7 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center mb-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", component: "h2", color: "secondary", className: "py-2 font-medium uppercase text-sm text-surface-600 dark:text-surface-400", children: "Quick Start" }) });
183
+ if ($[13] !== t6) {
184
+ t7 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-8 pt-2", children: t6 });
185
+ $[13] = t6;
186
186
  $[14] = t7;
187
187
  } else {
188
188
  t7 = $[14];
189
189
  }
190
190
  let t8;
191
191
  if ($[15] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
192
- t8 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "body2", color: "secondary", className: "mb-4 max-w-2xl", children: [
192
+ t8 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center mb-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", component: "h2", color: "secondary", className: "py-2 font-medium uppercase text-sm text-surface-600 dark:text-surface-400", children: "Quick Start" }) });
193
+ $[15] = t8;
194
+ } else {
195
+ t8 = $[15];
196
+ }
197
+ let t9;
198
+ if ($[16] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
199
+ t9 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "body2", color: "secondary", className: "mb-4 max-w-2xl", children: [
193
200
  "Generate a fully-typed SDK from your collections with",
194
201
  " ",
195
202
  /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-emerald-400 font-mono text-xs bg-emerald-400/10 px-1.5 py-0.5 rounded", children: "npx rebase generate-sdk" }),
196
203
  " ",
197
204
  "and start querying your data with full TypeScript autocompletion."
198
205
  ] });
199
- $[15] = t8;
206
+ $[16] = t9;
200
207
  } else {
201
- t8 = $[15];
208
+ t9 = $[16];
202
209
  }
203
- let t9;
204
- if ($[16] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
205
- t9 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-200/40 dark:border-surface-700/40 bg-surface-50 dark:bg-surface-900/80", children: [
210
+ let t10;
211
+ if ($[17] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
212
+ t10 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-200/40 dark:border-surface-700/40 bg-surface-50 dark:bg-surface-900/80", children: [
206
213
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
207
214
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1.5", children: [
208
215
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-2.5 h-2.5 rounded-full bg-red-400/60" }),
@@ -213,63 +220,64 @@
213
220
  ] }),
214
221
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-surface-400 dark:text-surface-500", children: "TypeScript" })
215
222
  ] });
216
- $[16] = t9;
223
+ $[17] = t10;
217
224
  } else {
218
- t9 = $[16];
225
+ t10 = $[17];
219
226
  }
220
- let t10;
221
- if ($[17] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
222
- t10 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-10 mb-6", children: [
223
- t7,
227
+ let t11;
228
+ if ($[18] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
229
+ t11 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-10 mb-6", children: [
224
230
  t8,
231
+ t9,
225
232
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-surface-200/40 dark:border-surface-700/40 bg-white dark:bg-surface-950 overflow-hidden", children: [
226
- t9,
233
+ t10,
227
234
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-4 overflow-x-auto text-[13px] leading-6 font-mono", children: /* @__PURE__ */ jsxRuntime.jsx(SyntaxHighlightedSnippet, {}) })
228
235
  ] })
229
236
  ] });
230
- $[17] = t10;
237
+ $[18] = t11;
231
238
  } else {
232
- t10 = $[17];
239
+ t11 = $[18];
233
240
  }
234
- let t11;
235
- if ($[18] !== sections) {
236
- t11 = sections?.map(_temp$6);
237
- $[18] = sections;
238
- $[19] = t11;
241
+ let t12;
242
+ if ($[19] !== sections) {
243
+ t12 = sections?.map(_temp$7);
244
+ $[19] = sections;
245
+ $[20] = t12;
239
246
  } else {
240
- t11 = $[19];
247
+ t12 = $[20];
241
248
  }
242
- let t12;
243
- if ($[20] !== additionalChildrenEnd || $[21] !== additionalChildrenStart || $[22] !== t11 || $[23] !== t4 || $[24] !== t6) {
244
- t12 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { maxWidth: "6xl", children: [
249
+ let t13;
250
+ if ($[21] !== additionalChildrenEnd || $[22] !== additionalChildrenStart || $[23] !== t12 || $[24] !== t5 || $[25] !== t7) {
251
+ t13 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { maxWidth: "6xl", children: [
245
252
  t4,
253
+ t5,
246
254
  additionalChildrenStart,
247
- t6,
248
- t10,
255
+ t7,
249
256
  t11,
257
+ t12,
250
258
  additionalChildrenEnd
251
259
  ] });
252
- $[20] = additionalChildrenEnd;
253
- $[21] = additionalChildrenStart;
254
- $[22] = t11;
255
- $[23] = t4;
256
- $[24] = t6;
257
- $[25] = t12;
260
+ $[21] = additionalChildrenEnd;
261
+ $[22] = additionalChildrenStart;
262
+ $[23] = t12;
263
+ $[24] = t5;
264
+ $[25] = t7;
265
+ $[26] = t13;
258
266
  } else {
259
- t12 = $[25];
267
+ t13 = $[26];
260
268
  }
261
- let t13;
262
- if ($[26] !== containerRef || $[27] !== t12) {
263
- t13 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "py-2 overflow-auto h-full w-full", children: t12 });
264
- $[26] = containerRef;
265
- $[27] = t12;
269
+ let t14;
270
+ if ($[27] !== containerRef || $[28] !== t13) {
271
+ t14 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "py-2 overflow-auto h-full w-full", children: t13 });
272
+ $[27] = containerRef;
266
273
  $[28] = t13;
274
+ $[29] = t14;
267
275
  } else {
268
- t13 = $[28];
276
+ t14 = $[29];
269
277
  }
270
- return t13;
278
+ return t14;
271
279
  }
272
- function _temp$6(s) {
280
+ function _temp$7(s) {
273
281
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-10", children: [
274
282
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", component: "h2", color: "secondary", className: "p-4 py-2 rounded font-medium uppercase text-sm text-surface-600 dark:text-surface-400", children: s.title }),
275
283
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4", children: s.children })
@@ -897,12 +905,12 @@
897
905
  /* @__PURE__ */ jsxRuntime.jsx("svg", { className: ui.cls("w-3 h-3 mr-1 transition-transform shrink-0", expandedTables[`${schemaName}.${table.tableName}`] ? "rotate-90" : ""), fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" }) }),
898
906
  /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3.5 h-3.5 mr-1 shrink-0 text-text-disabled dark:text-text-disabled-dark", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" }) }),
899
907
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-text-secondary dark:text-text-secondary-dark text-xs truncate flex-1 min-w-0", children: table.tableName }),
900
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex opacity-0 group-hover:opacity-100 focus-within:opacity-100 absolute right-1 items-center bg-surface-100 dark:bg-surface-950 px-1 gap-1 rounded transition-opacity", children: [
901
- /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "smallest", className: "transition-colors text-text-secondary hover:text-text-primary pointer-events-auto", onClick: (e) => {
908
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex opacity-0 group-hover:opacity-100 focus-within:opacity-100 absolute right-1 items-center bg-surface-100 dark:bg-surface-800 px-1 gap-1 rounded transition-opacity", children: [
909
+ /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: (e) => {
902
910
  e.stopPropagation();
903
911
  navigator.clipboard.writeText(table.tableName);
904
- }, title: "CopyIcon table name", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyIcon, { size: ui.iconSize.smallest }) }),
905
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, { trigger: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "smallest", className: "transition-colors text-text-secondary hover:text-text-primary pointer-events-auto", onClick: (e_0) => e_0.stopPropagation(), title: "Generate SQL templates", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVerticalIcon, { size: ui.iconSize.smallest }) }), children: [
912
+ }, title: "CopyIcon table name", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyIcon, { size: ui.iconSize.small }) }),
913
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, { trigger: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: (e_0) => e_0.stopPropagation(), title: "Generate SQL templates", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVerticalIcon, { size: ui.iconSize.small }) }), children: [
906
914
  /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, { dense: true, className: "text-xs", onClick: (e_1) => {
907
915
  e_1.stopPropagation();
908
916
  onTableClick?.(`SELECT * FROM ${schemaName !== "public" ? `${schemaName}.` : ""}${table.tableName} LIMIT 100;`);
@@ -939,7 +947,7 @@ WHERE id = ?;`);
939
947
  /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3 h-3 mr-1.5 text-text-disabled dark:text-text-disabled-dark shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M9 4.5v15m6-15v15m-10.5-1.5h15c.621 0 1.125-.504 1.125-1.125V5.625c0-.621-.504-1.125-1.125-1.125h-15c-.621 0-1.125.504-1.125 1.125v12.75c0 .621.504 1.125 1.125 1.125Z" }) }),
940
948
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-primary dark:text-text-primary-dark text-[11px] truncate flex-grow mr-2", children: col.name }),
941
949
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark text-[9px] truncate mr-1 uppercase shrink-0", title: col.dataType, children: col.dataType }),
942
- /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "smallest", className: "opacity-0 group-hover:opacity-100 absolute right-1 bg-surface-50 dark:bg-surface-950 transition-colors pointer-events-auto", onClick: (e_6) => {
950
+ /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "smallest", className: "opacity-0 group-hover:opacity-100 absolute right-1 bg-surface-50 dark:bg-surface-800 transition-colors pointer-events-auto", onClick: (e_6) => {
943
951
  e_6.stopPropagation();
944
952
  navigator.clipboard.writeText(col.name);
945
953
  }, title: "CopyIcon column name", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyIcon, { size: ui.iconSize.smallest }) })
@@ -1520,7 +1528,7 @@ WHERE id = ?;`);
1520
1528
  }
1521
1529
  let t37;
1522
1530
  if ($[67] !== expanded || $[68] !== hasChildren || $[69] !== plan.Plans) {
1523
- t37 = expanded && hasChildren && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col space-y-2 mt-[-4px]", children: plan.Plans.map(_temp$5) });
1531
+ t37 = expanded && hasChildren && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col space-y-2 mt-[-4px]", children: plan.Plans.map(_temp$6) });
1524
1532
  $[67] = expanded;
1525
1533
  $[68] = hasChildren;
1526
1534
  $[69] = plan.Plans;
@@ -1547,7 +1555,7 @@ WHERE id = ?;`);
1547
1555
  }
1548
1556
  return t38;
1549
1557
  };
1550
- function _temp$5(childPlan, idx) {
1558
+ function _temp$6(childPlan, idx) {
1551
1559
  return /* @__PURE__ */ jsxRuntime.jsx(ExplainVisualizer, { plan: childPlan, isRoot: false }, idx);
1552
1560
  }
1553
1561
  let VirtualTableInput = null;
@@ -1559,7 +1567,7 @@ WHERE id = ?;`);
1559
1567
  const STORAGE_KEY_TABS = "rebase_sql_tabs";
1560
1568
  const STORAGE_KEY_ACTIVE_TAB = "rebase_sql_active_tab";
1561
1569
  const FixedEditorOverlay = (t0) => {
1562
- const $ = reactCompilerRuntime.c(29);
1570
+ const $ = reactCompilerRuntime.c(26);
1563
1571
  const {
1564
1572
  displayValue,
1565
1573
  onSave,
@@ -1650,90 +1658,70 @@ WHERE id = ?;`);
1650
1658
  t7 = $[9];
1651
1659
  }
1652
1660
  let t8;
1653
- if ($[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1661
+ if ($[10] !== resolvedMaxHeight) {
1654
1662
  t8 = {
1655
- minHeight: "32px"
1663
+ minHeight: "32px",
1664
+ maxHeight: resolvedMaxHeight
1656
1665
  };
1657
- $[10] = t8;
1666
+ $[10] = resolvedMaxHeight;
1667
+ $[11] = t8;
1658
1668
  } else {
1659
- t8 = $[10];
1669
+ t8 = $[11];
1660
1670
  }
1661
1671
  let t10;
1662
1672
  let t9;
1663
- if ($[11] !== resolvedMaxHeight) {
1664
- t9 = (e) => {
1665
- const val = e.target.value;
1666
- e.target.value = "";
1667
- e.target.value = val;
1668
- e.target.style.height = "auto";
1669
- e.target.style.height = `${Math.min(e.target.scrollHeight, resolvedMaxHeight)}px`;
1670
- };
1671
- t10 = (e_0) => {
1672
- e_0.target.style.height = "auto";
1673
- e_0.target.style.height = `${Math.min(e_0.target.scrollHeight, resolvedMaxHeight)}px`;
1674
- };
1675
- $[11] = resolvedMaxHeight;
1676
- $[12] = t10;
1677
- $[13] = t9;
1678
- } else {
1679
- t10 = $[12];
1680
- t9 = $[13];
1681
- }
1682
- let t11;
1683
- let t12;
1684
- if ($[14] !== onCancel || $[15] !== onSave) {
1685
- t11 = (e_1) => {
1686
- onSave(e_1.target.value || null);
1673
+ if ($[12] !== onCancel || $[13] !== onSave) {
1674
+ t9 = (e_0) => {
1675
+ onSave(e_0.target.value || null);
1687
1676
  onCancel();
1688
1677
  };
1689
- t12 = (e_2) => {
1690
- if (e_2.key === "Enter" && !e_2.shiftKey) {
1691
- e_2.preventDefault();
1692
- onSave(e_2.currentTarget.value || null);
1678
+ t10 = (e_1) => {
1679
+ if (e_1.key === "Enter" && !e_1.shiftKey) {
1680
+ e_1.preventDefault();
1681
+ onSave(e_1.currentTarget.value || null);
1693
1682
  onCancel();
1694
1683
  }
1695
- if (e_2.key === "Escape") {
1684
+ if (e_1.key === "Escape") {
1696
1685
  onCancel();
1697
1686
  }
1698
1687
  };
1699
- $[14] = onCancel;
1700
- $[15] = onSave;
1701
- $[16] = t11;
1702
- $[17] = t12;
1688
+ $[12] = onCancel;
1689
+ $[13] = onSave;
1690
+ $[14] = t10;
1691
+ $[15] = t9;
1703
1692
  } else {
1704
- t11 = $[16];
1705
- t12 = $[17];
1693
+ t10 = $[14];
1694
+ t9 = $[15];
1706
1695
  }
1707
- let t13;
1708
- if ($[18] !== displayValue || $[19] !== t10 || $[20] !== t11 || $[21] !== t12 || $[22] !== t9) {
1709
- t13 = /* @__PURE__ */ jsxRuntime.jsx("textarea", { className: "w-full h-full bg-transparent outline-none border-none ring-0 font-mono text-[13px] text-text-primary dark:text-text-primary-dark px-4 py-1.5 resize-none overflow-y-auto", defaultValue: displayValue, autoFocus: true, style: t8, onFocus: t9, onChange: t10, onBlur: t11, onKeyDown: t12 });
1710
- $[18] = displayValue;
1711
- $[19] = t10;
1696
+ let t11;
1697
+ if ($[16] !== displayValue || $[17] !== t10 || $[18] !== t8 || $[19] !== t9) {
1698
+ t11 = /* @__PURE__ */ jsxRuntime.jsx(ui.TextareaAutosize, { className: "w-full h-full bg-transparent outline-none border-none ring-0 font-mono text-[13px] text-text-primary dark:text-text-primary-dark px-4 py-1.5 resize-none overflow-y-auto", defaultValue: displayValue, autoFocus: true, style: t8, onFocus: _temp$5, onBlur: t9, onKeyDown: t10 });
1699
+ $[16] = displayValue;
1700
+ $[17] = t10;
1701
+ $[18] = t8;
1702
+ $[19] = t9;
1712
1703
  $[20] = t11;
1713
- $[21] = t12;
1714
- $[22] = t9;
1715
- $[23] = t13;
1716
1704
  } else {
1717
- t13 = $[23];
1705
+ t11 = $[20];
1718
1706
  }
1719
- let t14;
1720
- if ($[24] !== t13 || $[25] !== t7) {
1721
- t14 = reactDom.createPortal(/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed z-[9999] bg-surface-50 dark:bg-surface-900 border-2 border-primary dark:border-primary-dark shadow-xl flex flex-col", style: t7, children: t13 }), document.body);
1722
- $[24] = t13;
1723
- $[25] = t7;
1724
- $[26] = t14;
1707
+ let t12;
1708
+ if ($[21] !== t11 || $[22] !== t7) {
1709
+ t12 = reactDom.createPortal(/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed z-[9999] bg-surface-50 dark:bg-surface-900 border-2 border-primary dark:border-primary-dark shadow-xl flex flex-col", style: t7, children: t11 }), document.body);
1710
+ $[21] = t11;
1711
+ $[22] = t7;
1712
+ $[23] = t12;
1725
1713
  } else {
1726
- t14 = $[26];
1714
+ t12 = $[23];
1727
1715
  }
1728
- let t15;
1729
- if ($[27] !== t14) {
1730
- t15 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: anchorRef, className: "w-full h-full min-h-[20px]", children: t14 });
1731
- $[27] = t14;
1732
- $[28] = t15;
1716
+ let t13;
1717
+ if ($[24] !== t12) {
1718
+ t13 = /* @__PURE__ */ jsxRuntime.jsx("div", { ref: anchorRef, className: "w-full h-full min-h-[20px]", children: t12 });
1719
+ $[24] = t12;
1720
+ $[25] = t13;
1733
1721
  } else {
1734
- t15 = $[28];
1722
+ t13 = $[25];
1735
1723
  }
1736
- return t15;
1724
+ return t13;
1737
1725
  };
1738
1726
  const SQLEditor = () => {
1739
1727
  const {
@@ -2568,12 +2556,15 @@ WHERE id = ?;`);
2568
2556
  /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: handleAddTab, className: "ml-2 flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { size: ui.iconSize.smallest }) })
2569
2557
  ] }) }),
2570
2558
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center justify-end pr-2 gap-1.5", children: [
2571
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: t("studio_sql_format_sql"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: handlePrettify, className: "text-text-secondary hover:text-text-primary transition-colors", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MenuIcon, { size: ui.iconSize.smallest }) }) }),
2559
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: t("studio_sql_format_sql"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: handlePrettify, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MenuIcon, { size: ui.iconSize.smallest }) }) }),
2572
2560
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", size: "small", onClick: handleExplain, disabled: loading, children: t("studio_sql_explain") }),
2573
2561
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-px bg-surface-200 dark:bg-surface-950 mx-1" }),
2574
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2 px-2 cursor-pointer", onClick: () => setAutoLimit(!autoLimit), children: [
2562
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2 px-2", onClick: (e_14) => {
2563
+ setAutoLimit(!autoLimit);
2564
+ e_14.stopPropagation();
2565
+ }, children: [
2575
2566
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-[11px] text-text-secondary cursor-pointer select-none", children: t("studio_sql_limit_1000") }),
2576
- /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: autoLimit, onChange: (e_14) => setAutoLimit(e_14.target.checked), onClick: (e_15) => e_15.stopPropagation(), className: "w-3.5 h-3.5 rounded border-surface-300 text-primary focus:ring-primary cursor-pointer" })
2567
+ /* @__PURE__ */ jsxRuntime.jsx("div", { onClick: (e_15) => e_15.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { checked: autoLimit, onCheckedChange: setAutoLimit, size: "smallest", padding: false }) })
2577
2568
  ] }),
2578
2569
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-px bg-surface-200 dark:bg-surface-950 mx-1" }),
2579
2570
  /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: isFavorite ? t("studio_sql_remove_from_favorites") : t("studio_sql_add_to_favorites"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => {
@@ -2638,6 +2629,11 @@ WHERE id = ?;`);
2638
2629
  } })
2639
2630
  ] });
2640
2631
  };
2632
+ function _temp$5(e) {
2633
+ const val = e.target.value;
2634
+ e.target.value = "";
2635
+ e.target.value = val;
2636
+ }
2641
2637
  const SQLEditor$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
2642
2638
  __proto__: null,
2643
2639
  SQLEditor
@@ -3269,7 +3265,7 @@ return result;`);
3269
3265
  return t8;
3270
3266
  }
3271
3267
  function AuthSimulationSelector(t0) {
3272
- const $ = reactCompilerRuntime.c(27);
3268
+ const $ = reactCompilerRuntime.c(25);
3273
3269
  const {
3274
3270
  authMode,
3275
3271
  setAuthMode,
@@ -3290,77 +3286,65 @@ return result;`);
3290
3286
  t1 = $[0];
3291
3287
  t2 = $[1];
3292
3288
  }
3293
- let t3;
3289
+ const t3 = authMode === "jwt" ? "outlined" : "outlined";
3290
+ const t4 = authMode === "jwt" ? "primary" : "neutral";
3291
+ let t5;
3294
3292
  if ($[2] !== setAuthMode) {
3295
- t3 = () => setAuthMode("jwt");
3293
+ t5 = () => setAuthMode("jwt");
3296
3294
  $[2] = setAuthMode;
3297
- $[3] = t3;
3295
+ $[3] = t5;
3298
3296
  } else {
3299
- t3 = $[3];
3300
- }
3301
- const t4 = authMode === "jwt" ? "bg-primary/15 text-primary dark:text-primary-dark border-primary/30 font-medium" : "border-surface-300 dark:border-surface-600 text-text-secondary dark:text-text-secondary-dark hover:border-primary/30";
3302
- let t5;
3303
- if ($[4] !== t4) {
3304
- t5 = ui.cls("px-3 py-1 text-xs rounded-full border transition-all", t4);
3305
- $[4] = t4;
3306
- $[5] = t5;
3307
- } else {
3308
- t5 = $[5];
3297
+ t5 = $[3];
3309
3298
  }
3310
3299
  let t6;
3311
- if ($[6] !== t3 || $[7] !== t5) {
3312
- t6 = /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: t3, className: t5, children: "JWT Token" });
3313
- $[6] = t3;
3314
- $[7] = t5;
3315
- $[8] = t6;
3316
- } else {
3317
- t6 = $[8];
3318
- }
3319
- let t7;
3320
- if ($[9] !== setAuthMode) {
3321
- t7 = () => setAuthMode("none");
3322
- $[9] = setAuthMode;
3323
- $[10] = t7;
3300
+ if ($[4] !== t3 || $[5] !== t4 || $[6] !== t5) {
3301
+ t6 = /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: t3, color: t4, onClick: t5, className: "rounded-full !px-3 !py-1 !text-xs", children: "JWT Token" });
3302
+ $[4] = t3;
3303
+ $[5] = t4;
3304
+ $[6] = t5;
3305
+ $[7] = t6;
3324
3306
  } else {
3325
- t7 = $[10];
3307
+ t6 = $[7];
3326
3308
  }
3327
- const t8 = authMode === "none" ? "bg-red-500/15 text-red-600 dark:text-red-400 border-red-500/30 font-medium" : "border-surface-300 dark:border-surface-600 text-text-secondary dark:text-text-secondary-dark hover:border-red-500/30";
3309
+ const t7 = authMode === "none" ? "outlined" : "outlined";
3310
+ const t8 = authMode === "none" ? "error" : "neutral";
3328
3311
  let t9;
3329
- if ($[11] !== t8) {
3330
- t9 = ui.cls("px-3 py-1 text-xs rounded-full border transition-all", t8);
3331
- $[11] = t8;
3332
- $[12] = t9;
3312
+ if ($[8] !== setAuthMode) {
3313
+ t9 = () => setAuthMode("none");
3314
+ $[8] = setAuthMode;
3315
+ $[9] = t9;
3333
3316
  } else {
3334
- t9 = $[12];
3317
+ t9 = $[9];
3335
3318
  }
3336
3319
  let t10;
3337
- if ($[13] !== t7 || $[14] !== t9) {
3338
- t10 = /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: t7, className: t9, children: "No Auth" });
3339
- $[13] = t7;
3340
- $[14] = t9;
3341
- $[15] = t10;
3320
+ if ($[10] !== t7 || $[11] !== t8 || $[12] !== t9) {
3321
+ t10 = /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: t7, color: t8, onClick: t9, className: "rounded-full !px-3 !py-1 !text-xs", children: "No Auth" });
3322
+ $[10] = t7;
3323
+ $[11] = t8;
3324
+ $[12] = t9;
3325
+ $[13] = t10;
3342
3326
  } else {
3343
- t10 = $[15];
3327
+ t10 = $[13];
3344
3328
  }
3345
3329
  let t11;
3346
- if ($[16] !== authMode || $[17] !== currentUser || $[18] !== loading || $[19] !== selectedUser || $[20] !== setSelectedUser || $[21] !== users) {
3330
+ if ($[14] !== authMode || $[15] !== currentUser || $[16] !== loading || $[17] !== selectedUser || $[18] !== setSelectedUser || $[19] !== users) {
3347
3331
  t11 = authMode === "jwt" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3348
3332
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-surface-300 dark:bg-surface-600 mx-1" }),
3349
3333
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark text-xs font-medium", children: "Run as:" }),
3350
3334
  /* @__PURE__ */ jsxRuntime.jsx(core.UserSelectPopover, { selectedUser, onUserSelected: setSelectedUser, users, loading, currentUser })
3351
3335
  ] });
3352
- $[16] = authMode;
3353
- $[17] = currentUser;
3354
- $[18] = loading;
3355
- $[19] = selectedUser;
3356
- $[20] = setSelectedUser;
3357
- $[21] = users;
3358
- $[22] = t11;
3336
+ $[14] = authMode;
3337
+ $[15] = currentUser;
3338
+ $[16] = loading;
3339
+ $[17] = selectedUser;
3340
+ $[18] = setSelectedUser;
3341
+ $[19] = users;
3342
+ $[20] = t11;
3359
3343
  } else {
3360
- t11 = $[22];
3344
+ t11 = $[20];
3361
3345
  }
3362
3346
  let t12;
3363
- if ($[23] !== t10 || $[24] !== t11 || $[25] !== t6) {
3347
+ if ($[21] !== t10 || $[22] !== t11 || $[23] !== t6) {
3364
3348
  t12 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
3365
3349
  t1,
3366
3350
  t2,
@@ -3368,12 +3352,12 @@ return result;`);
3368
3352
  t10,
3369
3353
  t11
3370
3354
  ] });
3371
- $[23] = t10;
3372
- $[24] = t11;
3373
- $[25] = t6;
3374
- $[26] = t12;
3355
+ $[21] = t10;
3356
+ $[22] = t11;
3357
+ $[23] = t6;
3358
+ $[24] = t12;
3375
3359
  } else {
3376
- t12 = $[26];
3360
+ t12 = $[24];
3377
3361
  }
3378
3362
  return t12;
3379
3363
  }
@@ -5419,6 +5403,12 @@ return result;
5419
5403
  function _temp2$2(role) {
5420
5404
  return /* @__PURE__ */ jsxRuntime.jsx(ui.MultiSelectItem, { value: role, children: role }, role);
5421
5405
  }
5406
+ function sanitizeSqlIdentifier(name) {
5407
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
5408
+ throw new Error(`Invalid SQL identifier: "${name}". Only letters, digits, and underscores are allowed.`);
5409
+ }
5410
+ return `"${name}"`;
5411
+ }
5422
5412
  const RLSEditor = ({
5423
5413
  apiUrl = ""
5424
5414
  }) => {
@@ -5694,6 +5684,30 @@ return result;
5694
5684
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark text-[11px]", children: "Total policies" }),
5695
5685
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "font-mono text-[13px] font-medium", children: rlsStats.totalPolicies })
5696
5686
  ] })
5687
+ ] }),
5688
+ rlsStats.total - rlsStats.enabled > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("p-2.5 rounded border border-yellow-200 dark:border-yellow-900/50 bg-yellow-50 dark:bg-yellow-900/20 flex items-start gap-2", ui.defaultBorderMixin), children: [
5689
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangleIcon, { size: 14, className: "text-yellow-600 dark:text-yellow-500 mt-0.5 shrink-0" }),
5690
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5691
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", className: "text-yellow-800 dark:text-yellow-400 text-[11px] font-semibold block", children: [
5692
+ rlsStats.total - rlsStats.enabled,
5693
+ " table",
5694
+ rlsStats.total - rlsStats.enabled > 1 ? "s" : "",
5695
+ " without RLS"
5696
+ ] }),
5697
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-yellow-700 dark:text-yellow-600 text-[10px] block mt-0.5", children: "These tables have no row-level access control. If auth enforcement is disabled, data may be publicly accessible." })
5698
+ ] })
5699
+ ] }),
5700
+ rlsStats.enabled > 0 && rlsStats.enabled - rlsStats.withPolicies > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("p-2.5 rounded border border-blue-200 dark:border-blue-900/50 bg-blue-50 dark:bg-blue-900/20 flex items-start gap-2", ui.defaultBorderMixin), children: [
5701
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldIcon, { size: 14, className: "text-blue-600 dark:text-blue-400 mt-0.5 shrink-0" }),
5702
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5703
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", className: "text-blue-800 dark:text-blue-300 text-[11px] font-semibold block", children: [
5704
+ rlsStats.enabled - rlsStats.withPolicies,
5705
+ " table",
5706
+ rlsStats.enabled - rlsStats.withPolicies > 1 ? "s" : "",
5707
+ " with RLS but no policies"
5708
+ ] }),
5709
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-blue-700 dark:text-blue-500 text-[10px] block mt-0.5", children: "RLS is enabled but no permissive policies exist. All access is denied by default (Postgres deny-all)." })
5710
+ ] })
5697
5711
  ] })
5698
5712
  ] })
5699
5713
  ] })
@@ -5710,7 +5724,7 @@ return result;
5710
5724
  const action = activeTableData.rlsEnabled ? "DISABLE" : "ENABLE";
5711
5725
  if (!confirm(`Are you sure you want to ${action.toLowerCase()} Row Level Security on "${table_3}"?`)) return;
5712
5726
  try {
5713
- await databaseAdmin.executeSql(`ALTER TABLE "${table_3}" ${action} ROW LEVEL SECURITY`);
5727
+ await databaseAdmin.executeSql(`ALTER TABLE ${sanitizeSqlIdentifier(table_3)} ${action} ROW LEVEL SECURITY`);
5714
5728
  snackbarController.open({
5715
5729
  type: "success",
5716
5730
  message: `RLS ${action.toLowerCase()}d on ${table_3}`
@@ -5729,7 +5743,7 @@ return result;
5729
5743
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", color: "primary", disabled: !activeCollection, onClick: () => setEditingPolicy("new"), children: t("studio_rls_create_policy") })
5730
5744
  ] }) })
5731
5745
  ] }),
5732
- error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 h-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(core.ErrorView, { title: t("studio_rls_error"), error, onRetry: fetchRLSData }) }) : !activeTableData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow flex items-center justify-center text-text-disabled h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
5746
+ isLoading && !activeTableData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow flex items-center justify-center h-full", children: /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, { size: "small" }) }) : error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 h-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(core.ErrorView, { title: t("studio_rls_error"), error, onRetry: fetchRLSData }) }) : !activeTableData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow flex items-center justify-center text-text-disabled h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
5733
5747
  /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-12 h-12 mx-auto mb-4 opacity-50", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1, d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
5734
5748
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", children: t("studio_rls_select_table") })
5735
5749
  ] }) }) : editingPolicy ? /* @__PURE__ */ jsxRuntime.jsx(PolicyEditor, { policy: editingPolicy === "new" ? void 0 : editingPolicy, schema: activeTableData.schemaName, table: activeTableData.tableName, onSave: async (newPolicy) => {
@@ -5848,7 +5862,7 @@ return result;
5848
5862
  const table_4 = activeTableData.tableName;
5849
5863
  if (!confirm(`Drop policy "${policy.policyname}" from table "${table_4}"?`)) return;
5850
5864
  try {
5851
- await databaseAdmin.executeSql(`DROP POLICY "${policy.policyname}" ON "${table_4}"`);
5865
+ await databaseAdmin.executeSql(`DROP POLICY ${sanitizeSqlIdentifier(policy.policyname)} ON ${sanitizeSqlIdentifier(table_4)}`);
5852
5866
  snackbarController.open({
5853
5867
  type: "success",
5854
5868
  message: `Policy "${policy.policyname}" dropped`
@@ -5863,6 +5877,17 @@ return result;
5863
5877
  }, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2Icon, { size: ui.iconSize.smallest }) }) })
5864
5878
  ] })
5865
5879
  ] }, policy.policyname))
5880
+ ] }),
5881
+ activeTableData && mergedPolicies.length === 0 && activeTableData.rlsEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
5882
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldIcon, { size: 40, className: "text-surface-300 dark:text-surface-600 mb-4" }),
5883
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle2", className: "text-text-secondary dark:text-text-secondary-dark mb-2", children: "No policies defined" }),
5884
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark max-w-sm mb-4", children: "RLS is enabled on this table but no policies exist. All access is denied by default (Postgres deny-all). Create a policy to allow specific access." }),
5885
+ activeCollection && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "filled", color: "primary", onClick: () => setEditingPolicy("new"), children: t("studio_rls_create_policy") })
5886
+ ] }),
5887
+ activeTableData && mergedPolicies.length === 0 && !activeTableData.rlsEnabled && activeCollection && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
5888
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangleIcon, { size: 40, className: "text-yellow-400 dark:text-yellow-600 mb-4" }),
5889
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle2", className: "text-text-secondary dark:text-text-secondary-dark mb-2", children: "No access control" }),
5890
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark max-w-sm", children: "This table has neither RLS nor policies. Enable RLS and create policies to restrict row-level access." })
5866
5891
  ] })
5867
5892
  ] }) }) })
5868
5893
  ] }) }) });
@@ -5945,570 +5970,157 @@ return result;
5945
5970
  }
5946
5971
  }, [uploading, onClose]);
5947
5972
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Dialog, { open, onOpenChange: (o) => !o && handleClose(), maxWidth: "md", children: [
5948
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { className: "p-0", children: [
5949
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 border-b border-surface-accent-200 dark:border-surface-accent-700", children: [
5950
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "h6", children: "Upload Files" }),
5951
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark mt-1 block", children: [
5952
- "to ",
5953
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-primary", children: [
5954
- "/",
5955
- currentPath || "root"
5956
- ] })
5973
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogTitle, { children: [
5974
+ "Upload Files",
5975
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark mt-0.5 block", children: [
5976
+ "to ",
5977
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-primary", children: [
5978
+ "/",
5979
+ currentPath || "root"
5957
5980
  ] })
5958
- ] }),
5959
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
5960
- /* @__PURE__ */ jsxRuntime.jsx(ui.FileUpload, { accept: {}, onFilesAdded: handleFilesAdded, size: "large", uploadDescription: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center pointer-events-none mt-2", children: [
5961
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UploadCloudIcon, { className: "text-surface-accent-400 mb-2 w-8 h-8" }),
5962
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "h6", className: "font-bold", children: "Drop files here or click to browse" }),
5963
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 font-medium", children: "Any file type supported" })
5964
- ] }) }),
5965
- error && /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-red-500 mt-2 block whitespace-pre-line", children: error }),
5966
- selectedFiles.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-2", children: [
5967
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", className: "text-surface-accent-500", children: [
5968
- "Selected files (",
5969
- selectedFiles.length,
5970
- ")"
5981
+ ] })
5982
+ ] }),
5983
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { className: "space-y-4", children: [
5984
+ /* @__PURE__ */ jsxRuntime.jsx(ui.FileUpload, { onFilesAdded: handleFilesAdded, size: "large", uploadDescription: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center pointer-events-none", children: [
5985
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UploadCloudIcon, { className: "text-surface-accent-400 mb-2 w-8 h-8" }),
5986
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "label", children: "Drop files here or click to browse" }),
5987
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", color: "secondary", children: "Any file type supported" })
5988
+ ] }) }),
5989
+ error && /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-red-500 block whitespace-pre-line", children: error }),
5990
+ selectedFiles.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
5991
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", color: "secondary", children: [
5992
+ "Selected files (",
5993
+ selectedFiles.length,
5994
+ ")"
5995
+ ] }),
5996
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-40 overflow-auto space-y-1", children: selectedFiles.map((file, index_0) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-2 rounded bg-surface-100 dark:bg-surface-800", children: [
5997
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 mr-2", children: [
5998
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "truncate", children: file.name }),
5999
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", color: "secondary", children: formatFileSize(file.size) })
5971
6000
  ] }),
5972
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-40 overflow-auto space-y-1", children: selectedFiles.map((file, index_0) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex items-center justify-between p-2 rounded", "bg-surface-accent-50 dark:bg-surface-accent-800"), children: [
5973
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 mr-2", children: [
5974
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "truncate", children: file.name }),
5975
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500", children: formatFileSize(file.size) })
5976
- ] }),
5977
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", size: "small", onClick: (e) => {
5978
- e.stopPropagation();
5979
- handleRemoveFile(index_0);
5980
- }, disabled: uploading, children: "Remove" })
5981
- ] }, `${file.name}-${index_0}`)) })
5982
- ] })
6001
+ /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: (e) => {
6002
+ e.stopPropagation();
6003
+ handleRemoveFile(index_0);
6004
+ }, disabled: uploading, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { size: 14 }) })
6005
+ ] }, `${file.name}-${index_0}`)) })
5983
6006
  ] })
5984
6007
  ] }),
5985
6008
  /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogActions, { children: [
5986
6009
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", onClick: handleClose, disabled: uploading, children: "Cancel" }),
5987
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "filled", onClick: handleUpload, disabled: selectedFiles.length === 0 || uploading, children: uploading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5988
- /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, { size: "smallest" }),
5989
- "Uploading..."
5990
- ] }) : `Upload ${selectedFiles.length > 0 ? `(${selectedFiles.length})` : ""}` })
6010
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "filled", onClick: handleUpload, disabled: selectedFiles.length === 0 || uploading, startIcon: uploading ? /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, { size: "smallest" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UploadCloudIcon, { size: 14 }), children: uploading ? "Uploading..." : `Upload${selectedFiles.length > 0 ? ` (${selectedFiles.length})` : ""}` })
5991
6011
  ] })
5992
6012
  ] });
5993
6013
  }
5994
- function FilePreviewPanel(t0) {
5995
- const $ = reactCompilerRuntime.c(79);
5996
- const {
5997
- file,
5998
- onClose,
5999
- onDelete,
6000
- downloadUrl
6001
- } = t0;
6014
+ function FilePreviewPanel({
6015
+ file,
6016
+ onClose,
6017
+ onDelete,
6018
+ downloadUrl
6019
+ }) {
6002
6020
  file.contentType?.startsWith("image/");
6003
6021
  file.contentType?.startsWith("video/");
6004
6022
  file.contentType?.startsWith("audio/");
6005
- let t1;
6006
- if ($[0] !== file.contentType) {
6007
- t1 = getFileIcon(file.contentType);
6008
- $[0] = file.contentType;
6009
- $[1] = t1;
6010
- } else {
6011
- t1 = $[1];
6012
- }
6013
- const FileIconComponent = t1;
6023
+ const FileIconComponent = getFileIcon(file.contentType);
6014
6024
  const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false);
6015
- let t2;
6016
- let t3;
6017
- if ($[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6018
- t2 = ui.cls("flex flex-col h-full border-l", ui.defaultBorderMixin, "bg-white dark:bg-surface-950");
6019
- t3 = ui.cls("flex items-center justify-between p-3 border-b shrink-0", ui.defaultBorderMixin);
6020
- $[2] = t2;
6021
- $[3] = t3;
6022
- } else {
6023
- t2 = $[2];
6024
- t3 = $[3];
6025
- }
6026
- let t4;
6027
- if ($[4] !== file.name) {
6028
- t4 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "font-medium truncate flex-1 mr-2", children: file.name });
6029
- $[4] = file.name;
6030
- $[5] = t4;
6031
- } else {
6032
- t4 = $[5];
6033
- }
6034
- let t5;
6035
- if ($[6] !== downloadUrl) {
6036
- t5 = downloadUrl && /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Download", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => window.open(downloadUrl, "_blank"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { size: ui.iconSize.smallest }) }) });
6037
- $[6] = downloadUrl;
6038
- $[7] = t5;
6039
- } else {
6040
- t5 = $[7];
6041
- }
6042
- let t6;
6043
- if ($[8] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6044
- t6 = () => setDeleteDialogOpen(true);
6045
- $[8] = t6;
6046
- } else {
6047
- t6 = $[8];
6048
- }
6049
- let t7;
6050
- if ($[9] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6051
- t7 = /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Delete", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: t6, className: "text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2Icon, { size: ui.iconSize.smallest }) }) });
6052
- $[9] = t7;
6053
- } else {
6054
- t7 = $[9];
6055
- }
6056
- let t8;
6057
- if ($[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6058
- t8 = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { size: ui.iconSize.smallest });
6059
- $[10] = t8;
6060
- } else {
6061
- t8 = $[10];
6062
- }
6063
- let t9;
6064
- if ($[11] !== onClose) {
6065
- t9 = /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: onClose, children: t8 });
6066
- $[11] = onClose;
6067
- $[12] = t9;
6068
- } else {
6069
- t9 = $[12];
6070
- }
6071
- let t10;
6072
- if ($[13] !== t5 || $[14] !== t9) {
6073
- t10 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
6074
- t5,
6075
- t7,
6076
- t9
6077
- ] });
6078
- $[13] = t5;
6079
- $[14] = t9;
6080
- $[15] = t10;
6081
- } else {
6082
- t10 = $[15];
6083
- }
6084
- let t11;
6085
- if ($[16] !== t10 || $[17] !== t4) {
6086
- t11 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t3, children: [
6087
- t4,
6088
- t10
6089
- ] });
6090
- $[16] = t10;
6091
- $[17] = t4;
6092
- $[18] = t11;
6093
- } else {
6094
- t11 = $[18];
6095
- }
6096
- let t12;
6097
- const ext = getExtension(file.name)?.toLowerCase() || "";
6098
- const isImage_0 = file.contentType?.startsWith("image/") || ["jpg", "jpeg", "png", "gif", "webp", "svg"].includes(ext);
6099
- const isVideo_0 = file.contentType?.startsWith("video/") || ["mp4", "webm", "ogg", "mov"].includes(ext);
6100
- const isAudio_0 = file.contentType?.startsWith("audio/") || ["mp3", "wav", "ogg", "m4a"].includes(ext);
6101
- const downloadUrl_0 = file.downloadUrl;
6102
- if (isImage_0 && downloadUrl_0) {
6103
- let t132;
6104
- if ($[19] !== downloadUrl_0 || $[20] !== file.name) {
6105
- t132 = /* @__PURE__ */ jsxRuntime.jsx("img", { src: downloadUrl_0, alt: file.name, className: "max-w-full max-h-[400px] object-contain rounded-md shadow-sm" });
6106
- $[19] = downloadUrl_0;
6107
- $[20] = file.name;
6108
- $[21] = t132;
6109
- } else {
6110
- t132 = $[21];
6111
- }
6112
- t12 = t132;
6113
- } else {
6114
- if (isVideo_0 && downloadUrl_0) {
6115
- let t132;
6116
- if ($[22] !== downloadUrl_0) {
6117
- t132 = /* @__PURE__ */ jsxRuntime.jsx("video", { src: downloadUrl_0, className: "max-w-full max-h-[400px] rounded-md", controls: true });
6118
- $[22] = downloadUrl_0;
6119
- $[23] = t132;
6120
- } else {
6121
- t132 = $[23];
6122
- }
6123
- t12 = t132;
6124
- } else {
6125
- if (isAudio_0 && downloadUrl_0) {
6126
- let t132;
6127
- if ($[24] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6128
- t132 = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Music2Icon, { className: "text-surface-accent-400 w-10 h-10" });
6129
- $[24] = t132;
6130
- } else {
6131
- t132 = $[24];
6132
- }
6133
- let t142;
6134
- if ($[25] !== downloadUrl_0) {
6135
- t142 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
6136
- t132,
6025
+ const [urlCopied, setUrlCopied] = React.useState(false);
6026
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex flex-col h-full border-l", ui.defaultBorderMixin, "bg-white dark:bg-surface-800"), children: [
6028
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex items-center justify-between p-3 border-b shrink-0", ui.defaultBorderMixin), children: [
6029
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "font-medium truncate flex-1 mr-2", children: file.name }),
6030
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
6031
+ downloadUrl && /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Download", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => window.open(downloadUrl, "_blank"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { size: ui.iconSize.smallest }) }) }),
6032
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Delete", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => setDeleteDialogOpen(true), className: "text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2Icon, { size: ui.iconSize.smallest }) }) }),
6033
+ /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { size: ui.iconSize.smallest }) })
6034
+ ] })
6035
+ ] }),
6036
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cls("flex flex-col items-center justify-center min-h-[200px] p-4 bg-surface-50 dark:bg-surface-800 border-b", ui.defaultBorderMixin), children: (() => {
6037
+ const ext = getExtension(file.name)?.toLowerCase() || "";
6038
+ const isImage_0 = file.contentType?.startsWith("image/") || ["jpg", "jpeg", "png", "gif", "webp", "svg"].includes(ext);
6039
+ const isVideo_0 = file.contentType?.startsWith("video/") || ["mp4", "webm", "ogg", "mov"].includes(ext);
6040
+ const isAudio_0 = file.contentType?.startsWith("audio/") || ["mp3", "wav", "ogg", "m4a"].includes(ext);
6041
+ const downloadUrl_0 = file.downloadUrl;
6042
+ if (isImage_0 && downloadUrl_0) {
6043
+ return /* @__PURE__ */ jsxRuntime.jsx("img", { src: downloadUrl_0, alt: file.name, className: "max-w-full max-h-[400px] object-contain rounded-md shadow-sm" });
6044
+ } else if (isVideo_0 && downloadUrl_0) {
6045
+ return /* @__PURE__ */ jsxRuntime.jsx("video", { src: downloadUrl_0, className: "max-w-full max-h-[400px] rounded-md", controls: true });
6046
+ } else if (isAudio_0 && downloadUrl_0) {
6047
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
6048
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Music2Icon, { className: "text-surface-accent-400 w-10 h-10" }),
6137
6049
  /* @__PURE__ */ jsxRuntime.jsx("audio", { src: downloadUrl_0, controls: true, className: "w-full max-w-xs" })
6138
6050
  ] });
6139
- $[25] = downloadUrl_0;
6140
- $[26] = t142;
6141
- } else {
6142
- t142 = $[26];
6143
- }
6144
- t12 = t142;
6145
- } else {
6146
- let t132;
6147
- if ($[27] !== FileIconComponent) {
6148
- t132 = /* @__PURE__ */ jsxRuntime.jsx(FileIconComponent, { className: "w-10 h-10" });
6149
- $[27] = FileIconComponent;
6150
- $[28] = t132;
6151
- } else {
6152
- t132 = $[28];
6153
- }
6154
- let t142;
6155
- if ($[29] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6156
- t142 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark", children: "No preview available" });
6157
- $[29] = t142;
6158
6051
  } else {
6159
- t142 = $[29];
6160
- }
6161
- let t152;
6162
- if ($[30] !== t132) {
6163
- t152 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3 text-surface-accent-400", children: [
6164
- t132,
6165
- t142
6052
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3 text-surface-accent-400", children: [
6053
+ /* @__PURE__ */ jsxRuntime.jsx(FileIconComponent, { className: "w-10 h-10" }),
6054
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark", children: "No preview available" })
6166
6055
  ] });
6167
- $[30] = t132;
6168
- $[31] = t152;
6169
- } else {
6170
- t152 = $[31];
6171
6056
  }
6172
- t12 = t152;
6173
- }
6174
- }
6175
- }
6176
- let t13;
6177
- if ($[32] !== t12) {
6178
- t13 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center min-h-[200px] p-4 bg-surface-50 dark:bg-surface-900 border-b border-surface-accent-200 dark:border-surface-accent-700", children: t12 }) });
6179
- $[32] = t12;
6180
- $[33] = t13;
6181
- } else {
6182
- t13 = $[33];
6183
- }
6184
- let t14;
6185
- if ($[34] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6186
- t14 = /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark text-[10px] uppercase tracking-wider font-bold mb-1 block", children: "File Info" }) });
6187
- $[34] = t14;
6188
- } else {
6189
- t14 = $[34];
6190
- }
6191
- let t15;
6192
- if ($[35] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6193
- t15 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Name" });
6194
- $[35] = t15;
6195
- } else {
6196
- t15 = $[35];
6197
- }
6198
- let t16;
6199
- if ($[36] !== file.name) {
6200
- t16 = /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6201
- t15,
6202
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] break-all", children: file.name })
6203
- ] });
6204
- $[36] = file.name;
6205
- $[37] = t16;
6206
- } else {
6207
- t16 = $[37];
6208
- }
6209
- let t17;
6210
- if ($[38] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6211
- t17 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Type" });
6212
- $[38] = t17;
6213
- } else {
6214
- t17 = $[38];
6215
- }
6216
- const t18 = file.contentType || "Unknown";
6217
- let t19;
6218
- if ($[39] !== t18) {
6219
- t19 = /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6220
- t17,
6221
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px]", children: t18 })
6222
- ] });
6223
- $[39] = t18;
6224
- $[40] = t19;
6225
- } else {
6226
- t19 = $[40];
6227
- }
6228
- let t20;
6229
- if ($[41] !== file.size) {
6230
- t20 = file.size !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6231
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Size" }),
6232
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px]", children: formatFileSize(file.size) })
6233
- ] });
6234
- $[41] = file.size;
6235
- $[42] = t20;
6236
- } else {
6237
- t20 = $[42];
6238
- }
6239
- let t21;
6240
- if ($[43] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6241
- t21 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Extension" });
6242
- $[43] = t21;
6243
- } else {
6244
- t21 = $[43];
6245
- }
6246
- let t22;
6247
- if ($[44] !== file.name) {
6248
- t22 = getExtension(file.name) || "—";
6249
- $[44] = file.name;
6250
- $[45] = t22;
6251
- } else {
6252
- t22 = $[45];
6253
- }
6254
- let t23;
6255
- if ($[46] !== t22) {
6256
- t23 = /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6257
- t21,
6258
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-mono", children: t22 })
6259
- ] });
6260
- $[46] = t22;
6261
- $[47] = t23;
6262
- } else {
6263
- t23 = $[47];
6264
- }
6265
- let t24;
6266
- if ($[48] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6267
- t24 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Path" });
6268
- $[48] = t24;
6269
- } else {
6270
- t24 = $[48];
6271
- }
6272
- let t25;
6273
- if ($[49] !== file.fullPath) {
6274
- t25 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2", children: [
6275
- t24,
6276
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-mono break-all", children: file.fullPath })
6277
- ] });
6278
- $[49] = file.fullPath;
6279
- $[50] = t25;
6280
- } else {
6281
- t25 = $[50];
6282
- }
6283
- let t26;
6284
- if ($[51] !== t16 || $[52] !== t19 || $[53] !== t20 || $[54] !== t23 || $[55] !== t25) {
6285
- t26 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
6286
- t16,
6287
- t19,
6288
- t20,
6289
- t23,
6290
- t25
6291
- ] });
6292
- $[51] = t16;
6293
- $[52] = t19;
6294
- $[53] = t20;
6295
- $[54] = t23;
6296
- $[55] = t25;
6297
- $[56] = t26;
6298
- } else {
6299
- t26 = $[56];
6300
- }
6301
- let t27;
6302
- if ($[57] !== downloadUrl) {
6303
- t27 = downloadUrl && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-2", children: [
6304
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px] block mb-1", children: "URL" }),
6305
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 rounded bg-surface-100 dark:bg-surface-950 cursor-pointer hover:bg-surface-200 dark:hover:bg-surface-700 transition-colors", onClick: () => {
6306
- navigator.clipboard.writeText(downloadUrl);
6307
- }, children: [
6308
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "font-mono text-[11px] break-all text-primary", children: downloadUrl }),
6309
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark text-[10px] block mt-1", children: "Click to copy" })
6310
- ] })
6311
- ] });
6312
- $[57] = downloadUrl;
6313
- $[58] = t27;
6314
- } else {
6315
- t27 = $[58];
6316
- }
6317
- let t28;
6318
- if ($[59] !== t26 || $[60] !== t27) {
6319
- t28 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-3", children: [
6320
- t14,
6321
- t26,
6322
- t27
6323
- ] });
6324
- $[59] = t26;
6325
- $[60] = t27;
6326
- $[61] = t28;
6327
- } else {
6328
- t28 = $[61];
6329
- }
6330
- let t29;
6331
- if ($[62] !== t11 || $[63] !== t13 || $[64] !== t28) {
6332
- t29 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t2, children: [
6333
- t11,
6334
- t13,
6335
- t28
6336
- ] });
6337
- $[62] = t11;
6338
- $[63] = t13;
6339
- $[64] = t28;
6340
- $[65] = t29;
6341
- } else {
6342
- t29 = $[65];
6343
- }
6344
- let t30;
6345
- if ($[66] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6346
- t30 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle1", className: "mb-2", children: "Delete File?" });
6347
- $[66] = t30;
6348
- } else {
6349
- t30 = $[66];
6350
- }
6351
- let t31;
6352
- if ($[67] !== file.name) {
6353
- t31 = /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { children: [
6354
- t30,
6355
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { className: "text-surface-accent-600 dark:text-surface-accent-400", children: [
6356
- 'Are you sure you want to delete "',
6357
- file.name,
6358
- '"? This action cannot be undone.'
6057
+ })() }) }),
6058
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-3", children: [
6059
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark text-[10px] uppercase tracking-wider font-bold mb-1 block", children: "File Info" }) }),
6060
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
6061
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6062
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Name" }),
6063
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] break-all", children: file.name })
6064
+ ] }),
6065
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6066
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Type" }),
6067
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px]", children: file.contentType || "Unknown" })
6068
+ ] }),
6069
+ file.size !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6070
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Size" }),
6071
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px]", children: formatFileSize(file.size) })
6072
+ ] }),
6073
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6074
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Extension" }),
6075
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-mono", children: getExtension(file.name) || "—" })
6076
+ ] }),
6077
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2", children: [
6078
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px]", children: "Path" }),
6079
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-mono break-all", children: file.fullPath })
6080
+ ] })
6081
+ ] }),
6082
+ downloadUrl && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-2", children: [
6083
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-surface-accent-500 text-[11px] block mb-1", children: "URL" }),
6084
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex items-center gap-2 p-2 rounded cursor-pointer transition-colors", "bg-surface-100 dark:bg-surface-800 hover:bg-surface-200 dark:hover:bg-surface-700"), onClick: () => {
6085
+ const fullUrl = downloadUrl.startsWith("http") ? downloadUrl : `${window.location.origin}${downloadUrl.startsWith("/") ? "" : "/"}${downloadUrl}`;
6086
+ navigator.clipboard.writeText(fullUrl).then(() => {
6087
+ setUrlCopied(true);
6088
+ setTimeout(() => setUrlCopied(false), 2e3);
6089
+ });
6090
+ }, children: [
6091
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "font-mono text-[11px] truncate flex-1 min-w-0 text-primary", children: (() => {
6092
+ const fullUrl_0 = downloadUrl.startsWith("http") ? downloadUrl : `${window.location.origin}${downloadUrl.startsWith("/") ? "" : "/"}${downloadUrl}`;
6093
+ return fullUrl_0;
6094
+ })() }),
6095
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: urlCopied ? "Copied!" : "Copy URL", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: urlCopied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { size: 14, className: "text-green-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyIcon, { size: 14, className: "text-surface-accent-400" }) }) })
6096
+ ] })
6097
+ ] })
6359
6098
  ] })
6360
- ] });
6361
- $[67] = file.name;
6362
- $[68] = t31;
6363
- } else {
6364
- t31 = $[68];
6365
- }
6366
- let t32;
6367
- if ($[69] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6368
- t32 = /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", onClick: () => setDeleteDialogOpen(false), children: "Cancel" });
6369
- $[69] = t32;
6370
- } else {
6371
- t32 = $[69];
6372
- }
6373
- let t33;
6374
- if ($[70] !== onDelete) {
6375
- t33 = /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogActions, { children: [
6376
- t32,
6377
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "filled", color: "error", onClick: () => {
6378
- setDeleteDialogOpen(false);
6379
- onDelete();
6380
- }, children: "Delete" })
6381
- ] });
6382
- $[70] = onDelete;
6383
- $[71] = t33;
6384
- } else {
6385
- t33 = $[71];
6386
- }
6387
- let t34;
6388
- if ($[72] !== deleteDialogOpen || $[73] !== t31 || $[74] !== t33) {
6389
- t34 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Dialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, children: [
6390
- t31,
6391
- t33
6392
- ] });
6393
- $[72] = deleteDialogOpen;
6394
- $[73] = t31;
6395
- $[74] = t33;
6396
- $[75] = t34;
6397
- } else {
6398
- t34 = $[75];
6399
- }
6400
- let t35;
6401
- if ($[76] !== t29 || $[77] !== t34) {
6402
- t35 = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6403
- t29,
6404
- t34
6405
- ] });
6406
- $[76] = t29;
6407
- $[77] = t34;
6408
- $[78] = t35;
6409
- } else {
6410
- t35 = $[78];
6411
- }
6412
- return t35;
6413
- }
6414
- function StorageSidebar(t0) {
6415
- const $ = reactCompilerRuntime.c(19);
6416
- const {
6417
- folders,
6418
- currentPath,
6419
- onNavigate,
6420
- loading
6421
- } = t0;
6422
- breadcrumbSegments(currentPath);
6423
- let t1;
6424
- let t2;
6425
- if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6426
- t1 = ui.cls("flex flex-col h-full w-full bg-white dark:bg-surface-950 border-r", ui.defaultBorderMixin);
6427
- t2 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cls("p-3 border-b flex justify-between items-center bg-surface-50 dark:bg-surface-900 shrink-0", ui.defaultBorderMixin), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "font-bold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark", children: "Folders" }) });
6428
- $[0] = t1;
6429
- $[1] = t2;
6430
- } else {
6431
- t1 = $[0];
6432
- t2 = $[1];
6433
- }
6434
- const t3 = currentPath === "" || !currentPath ? "bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-light" : "hover:bg-surface-100 dark:hover:bg-surface-950 text-text-secondary dark:text-text-secondary-dark";
6435
- let t4;
6436
- if ($[2] !== t3) {
6437
- t4 = ui.cls("flex items-center p-1.5 cursor-pointer rounded transition-colors", t3);
6438
- $[2] = t3;
6439
- $[3] = t4;
6440
- } else {
6441
- t4 = $[3];
6442
- }
6443
- let t5;
6444
- if ($[4] !== onNavigate) {
6445
- t5 = () => onNavigate("");
6446
- $[4] = onNavigate;
6447
- $[5] = t5;
6448
- } else {
6449
- t5 = $[5];
6450
- }
6451
- let t6;
6452
- let t7;
6453
- if ($[6] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
6454
- t6 = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HomeIcon, { size: ui.iconSize.smallest, className: "mr-1.5 shrink-0" });
6455
- t7 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-xs truncate", children: "Root" });
6456
- $[6] = t6;
6457
- $[7] = t7;
6458
- } else {
6459
- t6 = $[6];
6460
- t7 = $[7];
6461
- }
6462
- let t8;
6463
- if ($[8] !== t4 || $[9] !== t5) {
6464
- t8 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t4, onClick: t5, children: [
6465
- t6,
6466
- t7
6467
- ] });
6468
- $[8] = t4;
6469
- $[9] = t5;
6470
- $[10] = t8;
6471
- } else {
6472
- t8 = $[10];
6473
- }
6474
- let t9;
6475
- if ($[11] !== currentPath || $[12] !== folders || $[13] !== loading || $[14] !== onNavigate) {
6476
- t9 = loading && folders.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center p-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, { size: "small" }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 space-y-0.5", children: folders.map((folder) => {
6477
- const isSelected = currentPath === folder.fullPath;
6478
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex items-center p-1.5 cursor-pointer rounded transition-colors group", isSelected ? "bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-light" : "hover:bg-surface-100 dark:hover:bg-surface-950 text-text-secondary dark:text-text-secondary-dark"), onClick: () => onNavigate(folder.fullPath), children: [
6479
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderIcon, { size: ui.iconSize.smallest, className: "mr-1.5 shrink-0 text-amber-500 dark:text-amber-400" }),
6480
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-xs truncate flex-1 min-w-0", children: folder.name })
6481
- ] }, folder.fullPath);
6482
- }) });
6483
- $[11] = currentPath;
6484
- $[12] = folders;
6485
- $[13] = loading;
6486
- $[14] = onNavigate;
6487
- $[15] = t9;
6488
- } else {
6489
- t9 = $[15];
6490
- }
6491
- let t10;
6492
- if ($[16] !== t8 || $[17] !== t9) {
6493
- t10 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t1, children: [
6494
- t2,
6495
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow overflow-y-auto no-scrollbar p-1", children: [
6496
- t8,
6497
- t9
6099
+ ] }),
6100
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Dialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, children: [
6101
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { children: [
6102
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle1", className: "mb-2", children: "Delete File?" }),
6103
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { className: "text-surface-accent-600 dark:text-surface-accent-400", children: [
6104
+ 'Are you sure you want to delete "',
6105
+ file.name,
6106
+ '"? This action cannot be undone.'
6107
+ ] })
6108
+ ] }),
6109
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogActions, { children: [
6110
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", onClick: () => setDeleteDialogOpen(false), children: "Cancel" }),
6111
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "filled", color: "error", onClick: () => {
6112
+ setDeleteDialogOpen(false);
6113
+ onDelete();
6114
+ }, children: "Delete" })
6498
6115
  ] })
6499
- ] });
6500
- $[16] = t8;
6501
- $[17] = t9;
6502
- $[18] = t10;
6503
- } else {
6504
- t10 = $[18];
6505
- }
6506
- return t10;
6116
+ ] })
6117
+ ] });
6507
6118
  }
6508
6119
  const StorageView = () => {
6509
6120
  const storageSource = core.useStorageSource();
6510
6121
  const snackbarController = core.useSnackbarController();
6511
- const [currentPath, setCurrentPath] = React.useState("");
6122
+ const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
6123
+ const currentPath = searchParams.get("path") || "";
6512
6124
  const [loading, setLoading] = React.useState(true);
6513
6125
  const [error, setError] = React.useState(null);
6514
6126
  const [folders, setFolders] = React.useState([]);
@@ -6517,25 +6129,24 @@ return result;
6517
6129
  const [selectedDownloadUrl, setSelectedDownloadUrl] = React.useState(null);
6518
6130
  const [uploadDialogOpen, setUploadDialogOpen] = React.useState(false);
6519
6131
  const [viewMode, setViewMode] = React.useState("grid");
6520
- const [sidebarSize, setSidebarSize] = React.useState(() => {
6521
- try {
6522
- const saved = localStorage.getItem("rebase_storage_sidebar_size");
6523
- return saved !== null ? parseFloat(saved) : 18;
6524
- } catch {
6525
- return 18;
6526
- }
6527
- });
6132
+ const [selectedPaths, setSelectedPaths] = React.useState(/* @__PURE__ */ new Set());
6133
+ const lastClickedRef = React.useRef(null);
6134
+ const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false);
6135
+ const [deleteDialogTarget, setDeleteDialogTarget] = React.useState(null);
6136
+ const [deleting, setDeleting] = React.useState(false);
6137
+ const [newFolderDialogOpen, setNewFolderDialogOpen] = React.useState(false);
6138
+ const [newFolderName, setNewFolderName] = React.useState("");
6139
+ const [creatingFolder, setCreatingFolder] = React.useState(false);
6140
+ const apiConfig = core.useApiConfig();
6141
+ const storageSourceRef = React.useRef(storageSource);
6528
6142
  React.useEffect(() => {
6529
- try {
6530
- localStorage.setItem("rebase_storage_sidebar_size", sidebarSize.toString());
6531
- } catch {
6532
- }
6533
- }, [sidebarSize]);
6143
+ storageSourceRef.current = storageSource;
6144
+ }, [storageSource]);
6534
6145
  const fetchContents = React.useCallback(async (path) => {
6535
6146
  setLoading(true);
6536
6147
  setError(null);
6537
6148
  try {
6538
- const result = await storageSource.listObjects(path);
6149
+ const result = await storageSourceRef.current.listObjects(path);
6539
6150
  const folderItems = (result.prefixes ?? []).map((ref) => ({
6540
6151
  name: ref.name,
6541
6152
  fullPath: ref.fullPath,
@@ -6543,7 +6154,7 @@ return result;
6543
6154
  }));
6544
6155
  const fileItems = await Promise.all((result.items ?? []).map(async (ref_0) => {
6545
6156
  try {
6546
- const downloadConfig = await storageSource.getSignedUrl(ref_0.fullPath);
6157
+ const downloadConfig = await storageSourceRef.current.getSignedUrl(ref_0.fullPath);
6547
6158
  return {
6548
6159
  name: ref_0.name,
6549
6160
  fullPath: ref_0.fullPath,
@@ -6568,38 +6179,84 @@ return result;
6568
6179
  } finally {
6569
6180
  setLoading(false);
6570
6181
  }
6571
- }, [storageSource]);
6182
+ }, []);
6572
6183
  React.useEffect(() => {
6573
6184
  fetchContents(currentPath);
6574
6185
  }, [currentPath, fetchContents]);
6575
6186
  const handleNavigate = React.useCallback((path_0) => {
6576
- setCurrentPath(path_0);
6187
+ if (!path_0) {
6188
+ setSearchParams({});
6189
+ } else {
6190
+ setSearchParams({
6191
+ path: path_0
6192
+ });
6193
+ }
6577
6194
  setSelectedFile(null);
6578
6195
  setSelectedDownloadUrl(null);
6579
- }, []);
6196
+ setSelectedPaths(/* @__PURE__ */ new Set());
6197
+ lastClickedRef.current = null;
6198
+ }, [setSearchParams]);
6580
6199
  const handleNavigateUp = React.useCallback(() => {
6581
6200
  const parts = currentPath.split("/").filter(Boolean);
6582
6201
  parts.pop();
6583
6202
  handleNavigate(parts.join("/"));
6584
6203
  }, [currentPath, handleNavigate]);
6585
- const handleSelectFile = React.useCallback(async (file) => {
6586
- setSelectedFile(file);
6587
- if (file.downloadUrl) {
6588
- setSelectedDownloadUrl(file.downloadUrl);
6204
+ const allItems = React.useMemo(() => [...folders, ...files], [folders, files]);
6205
+ const handleItemClick = React.useCallback((item, e_0) => {
6206
+ const path_1 = item.fullPath;
6207
+ if (e_0.metaKey || e_0.ctrlKey) {
6208
+ setSelectedPaths((prev) => {
6209
+ const next = new Set(prev);
6210
+ if (next.has(path_1)) next.delete(path_1);
6211
+ else next.add(path_1);
6212
+ return next;
6213
+ });
6214
+ lastClickedRef.current = path_1;
6215
+ } else if (e_0.shiftKey && lastClickedRef.current) {
6216
+ const allPaths = allItems.map((i) => i.fullPath);
6217
+ const anchorIdx = allPaths.indexOf(lastClickedRef.current);
6218
+ const currentIdx = allPaths.indexOf(path_1);
6219
+ if (anchorIdx >= 0 && currentIdx >= 0) {
6220
+ const [start, end] = anchorIdx < currentIdx ? [anchorIdx, currentIdx] : [currentIdx, anchorIdx];
6221
+ setSelectedPaths((prev_0) => {
6222
+ const next_0 = new Set(prev_0);
6223
+ for (let i_0 = start; i_0 <= end; i_0++) next_0.add(allPaths[i_0]);
6224
+ return next_0;
6225
+ });
6226
+ }
6589
6227
  } else {
6590
- try {
6591
- const config = await storageSource.getSignedUrl(file.fullPath);
6592
- setSelectedDownloadUrl(config.url);
6593
- } catch {
6228
+ setSelectedPaths(/* @__PURE__ */ new Set([path_1]));
6229
+ lastClickedRef.current = path_1;
6230
+ if (!item.isFolder) {
6231
+ setSelectedFile(item);
6232
+ if (item.downloadUrl) {
6233
+ setSelectedDownloadUrl(item.downloadUrl);
6234
+ } else {
6235
+ storageSourceRef.current.getSignedUrl(item.fullPath).then((config) => setSelectedDownloadUrl(config.url)).catch(() => setSelectedDownloadUrl(null));
6236
+ }
6237
+ } else {
6238
+ setSelectedFile(null);
6594
6239
  setSelectedDownloadUrl(null);
6595
6240
  }
6596
6241
  }
6597
- }, [storageSource]);
6242
+ }, [allItems]);
6243
+ const handleItemDoubleClick = React.useCallback((item_0) => {
6244
+ if (item_0.isFolder) {
6245
+ handleNavigate(item_0.fullPath);
6246
+ } else {
6247
+ setSelectedFile(item_0);
6248
+ if (item_0.downloadUrl) {
6249
+ setSelectedDownloadUrl(item_0.downloadUrl);
6250
+ } else {
6251
+ storageSourceRef.current.getSignedUrl(item_0.fullPath).then((config_0) => setSelectedDownloadUrl(config_0.url)).catch(() => setSelectedDownloadUrl(null));
6252
+ }
6253
+ }
6254
+ }, [handleNavigate]);
6598
6255
  const handleUpload = React.useCallback(async (uploadFiles) => {
6599
- for (const file_0 of uploadFiles) {
6600
- const key = currentPath ? `${currentPath}/${file_0.name}` : file_0.name;
6601
- await storageSource.putObject({
6602
- file: file_0,
6256
+ for (const file of uploadFiles) {
6257
+ const key = currentPath ? `${currentPath}/${file.name}` : file.name;
6258
+ await storageSourceRef.current.putObject({
6259
+ file,
6603
6260
  key
6604
6261
  });
6605
6262
  }
@@ -6607,25 +6264,220 @@ return result;
6607
6264
  type: "success",
6608
6265
  message: `${uploadFiles.length} file${uploadFiles.length > 1 ? "s" : ""} uploaded successfully`
6609
6266
  });
6610
- fetchContents(currentPath);
6611
- }, [storageSource, currentPath, snackbarController, fetchContents]);
6267
+ await fetchContents(currentPath);
6268
+ }, [currentPath, snackbarController, fetchContents]);
6269
+ const handleCreateFolder = React.useCallback(async () => {
6270
+ if (!newFolderName.trim() || !apiConfig?.apiUrl) return;
6271
+ const name = newFolderName.trim();
6272
+ if (name.includes("/") || name.includes("\\")) {
6273
+ snackbarController.open({
6274
+ type: "error",
6275
+ message: "Folder name cannot contain slashes"
6276
+ });
6277
+ return;
6278
+ }
6279
+ const existingFolder = folders.find((f) => f.name === name);
6280
+ if (existingFolder) {
6281
+ snackbarController.open({
6282
+ type: "error",
6283
+ message: `Folder "${name}" already exists`
6284
+ });
6285
+ return;
6286
+ }
6287
+ setCreatingFolder(true);
6288
+ try {
6289
+ const folderPath = currentPath ? `default/${currentPath}/${name}` : `default/${name}`;
6290
+ const token = apiConfig.getAuthToken ? await apiConfig.getAuthToken() : null;
6291
+ const response = await fetch(`${apiConfig.apiUrl}/api/storage/folder`, {
6292
+ method: "POST",
6293
+ headers: {
6294
+ "Content-Type": "application/json",
6295
+ ...token ? {
6296
+ "Authorization": `Bearer ${token}`
6297
+ } : {}
6298
+ },
6299
+ body: JSON.stringify({
6300
+ path: folderPath
6301
+ })
6302
+ });
6303
+ if (!response.ok) {
6304
+ const err = await response.json().catch(() => ({
6305
+ error: "Failed to create folder"
6306
+ }));
6307
+ throw new Error(err.error || "Failed to create folder");
6308
+ }
6309
+ snackbarController.open({
6310
+ type: "success",
6311
+ message: `Folder "${name}" created`
6312
+ });
6313
+ setNewFolderDialogOpen(false);
6314
+ setNewFolderName("");
6315
+ await fetchContents(currentPath);
6316
+ } catch (e_1) {
6317
+ snackbarController.open({
6318
+ type: "error",
6319
+ message: e_1 instanceof Error ? e_1.message : String(e_1)
6320
+ });
6321
+ } finally {
6322
+ setCreatingFolder(false);
6323
+ }
6324
+ }, [newFolderName, currentPath, apiConfig, snackbarController, fetchContents, folders]);
6325
+ const handleDropFiles = React.useCallback(async (droppedFiles) => {
6326
+ if (droppedFiles.length === 0) return;
6327
+ try {
6328
+ for (const file_0 of droppedFiles) {
6329
+ const key_0 = currentPath ? `${currentPath}/${file_0.name}` : file_0.name;
6330
+ await storageSourceRef.current.putObject({
6331
+ file: file_0,
6332
+ key: key_0
6333
+ });
6334
+ }
6335
+ snackbarController.open({
6336
+ type: "success",
6337
+ message: `${droppedFiles.length} file${droppedFiles.length > 1 ? "s" : ""} uploaded successfully`
6338
+ });
6339
+ await fetchContents(currentPath);
6340
+ } catch (e_2) {
6341
+ snackbarController.open({
6342
+ type: "error",
6343
+ message: e_2 instanceof Error ? e_2.message : String(e_2)
6344
+ });
6345
+ }
6346
+ }, [currentPath, snackbarController, fetchContents]);
6347
+ const {
6348
+ getRootProps: getDropRootProps,
6349
+ getInputProps: getDropInputProps,
6350
+ isDragActive
6351
+ } = reactDropzone.useDropzone({
6352
+ onDrop: handleDropFiles,
6353
+ noClick: true,
6354
+ noKeyboard: true,
6355
+ noDragEventsBubbling: true
6356
+ });
6357
+ const deleteFolderRecursive = React.useCallback(async (prefix) => {
6358
+ const result_0 = await storageSourceRef.current.listObjects(prefix);
6359
+ for (const item_1 of result_0.items ?? []) {
6360
+ await storageSourceRef.current.deleteObject(item_1.fullPath);
6361
+ }
6362
+ for (const sub of result_0.prefixes ?? []) {
6363
+ await deleteFolderRecursive(sub.fullPath);
6364
+ }
6365
+ try {
6366
+ await storageSourceRef.current.deleteObject(prefix);
6367
+ } catch {
6368
+ }
6369
+ }, []);
6612
6370
  const handleDeleteFile = React.useCallback(async (file_1) => {
6613
6371
  try {
6614
- await storageSource.deleteObject(file_1.fullPath);
6372
+ if (file_1.isFolder) {
6373
+ await deleteFolderRecursive(file_1.fullPath);
6374
+ } else {
6375
+ await storageSourceRef.current.deleteObject(file_1.fullPath);
6376
+ }
6615
6377
  snackbarController.open({
6616
6378
  type: "success",
6617
6379
  message: `"${file_1.name}" deleted`
6618
6380
  });
6619
6381
  setSelectedFile(null);
6620
6382
  setSelectedDownloadUrl(null);
6383
+ setSelectedPaths((prev_1) => {
6384
+ const next_1 = new Set(prev_1);
6385
+ next_1.delete(file_1.fullPath);
6386
+ return next_1;
6387
+ });
6621
6388
  fetchContents(currentPath);
6622
- } catch (e_0) {
6389
+ } catch (e_3) {
6623
6390
  snackbarController.open({
6624
6391
  type: "error",
6625
- message: e_0 instanceof Error ? e_0.message : String(e_0)
6392
+ message: e_3 instanceof Error ? e_3.message : String(e_3)
6626
6393
  });
6627
6394
  }
6628
- }, [storageSource, currentPath, snackbarController, fetchContents]);
6395
+ }, [currentPath, snackbarController, fetchContents, deleteFolderRecursive]);
6396
+ const handleBulkDelete = React.useCallback(async () => {
6397
+ setDeleting(true);
6398
+ try {
6399
+ const items = allItems.filter((i_1) => selectedPaths.has(i_1.fullPath));
6400
+ for (const item_2 of items) {
6401
+ if (item_2.isFolder) {
6402
+ await deleteFolderRecursive(item_2.fullPath);
6403
+ } else {
6404
+ await storageSourceRef.current.deleteObject(item_2.fullPath);
6405
+ }
6406
+ }
6407
+ snackbarController.open({
6408
+ type: "success",
6409
+ message: `${items.length} item${items.length !== 1 ? "s" : ""} deleted`
6410
+ });
6411
+ setSelectedPaths(/* @__PURE__ */ new Set());
6412
+ setSelectedFile(null);
6413
+ setSelectedDownloadUrl(null);
6414
+ await fetchContents(currentPath);
6415
+ } catch (e_4) {
6416
+ snackbarController.open({
6417
+ type: "error",
6418
+ message: e_4 instanceof Error ? e_4.message : String(e_4)
6419
+ });
6420
+ } finally {
6421
+ setDeleting(false);
6422
+ setDeleteDialogOpen(false);
6423
+ setDeleteDialogTarget(null);
6424
+ }
6425
+ }, [allItems, selectedPaths, currentPath, snackbarController, fetchContents, deleteFolderRecursive]);
6426
+ const handleConfirmDeleteFolder = React.useCallback(async () => {
6427
+ if (!deleteDialogTarget || deleteDialogTarget === "selection") return;
6428
+ setDeleting(true);
6429
+ try {
6430
+ await deleteFolderRecursive(deleteDialogTarget.fullPath);
6431
+ snackbarController.open({
6432
+ type: "success",
6433
+ message: `Folder "${deleteDialogTarget.name}" deleted`
6434
+ });
6435
+ setSelectedPaths((prev_2) => {
6436
+ const next_2 = new Set(prev_2);
6437
+ next_2.delete(deleteDialogTarget.fullPath);
6438
+ return next_2;
6439
+ });
6440
+ await fetchContents(currentPath);
6441
+ } catch (e_5) {
6442
+ snackbarController.open({
6443
+ type: "error",
6444
+ message: e_5 instanceof Error ? e_5.message : String(e_5)
6445
+ });
6446
+ } finally {
6447
+ setDeleting(false);
6448
+ setDeleteDialogOpen(false);
6449
+ setDeleteDialogTarget(null);
6450
+ }
6451
+ }, [deleteDialogTarget, currentPath, snackbarController, fetchContents, deleteFolderRecursive]);
6452
+ const handleSelectAll = React.useCallback(() => {
6453
+ if (selectedPaths.size === allItems.length) {
6454
+ setSelectedPaths(/* @__PURE__ */ new Set());
6455
+ } else {
6456
+ setSelectedPaths(new Set(allItems.map((i_2) => i_2.fullPath)));
6457
+ }
6458
+ }, [allItems, selectedPaths]);
6459
+ React.useEffect(() => {
6460
+ const handler = (e_6) => {
6461
+ if (deleteDialogOpen || uploadDialogOpen || newFolderDialogOpen) return;
6462
+ if ((e_6.metaKey || e_6.ctrlKey) && e_6.key === "a") {
6463
+ e_6.preventDefault();
6464
+ handleSelectAll();
6465
+ }
6466
+ if (e_6.key === "Escape") {
6467
+ setSelectedPaths(/* @__PURE__ */ new Set());
6468
+ setSelectedFile(null);
6469
+ setSelectedDownloadUrl(null);
6470
+ }
6471
+ if ((e_6.key === "Delete" || e_6.key === "Backspace") && selectedPaths.size > 0 && !e_6.metaKey && !e_6.ctrlKey) {
6472
+ if (e_6.target?.tagName === "INPUT" || e_6.target?.tagName === "TEXTAREA") return;
6473
+ e_6.preventDefault();
6474
+ setDeleteDialogTarget("selection");
6475
+ setDeleteDialogOpen(true);
6476
+ }
6477
+ };
6478
+ window.addEventListener("keydown", handler);
6479
+ return () => window.removeEventListener("keydown", handler);
6480
+ }, [handleSelectAll, selectedPaths, deleteDialogOpen, uploadDialogOpen, newFolderDialogOpen]);
6629
6481
  const handleRefresh = React.useCallback(() => {
6630
6482
  fetchContents(currentPath);
6631
6483
  }, [currentPath, fetchContents]);
@@ -6640,43 +6492,74 @@ return result;
6640
6492
  if (error) {
6641
6493
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow flex items-center justify-center p-6 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(core.ErrorView, { title: "Error loading storage", error, onRetry: handleRefresh }) });
6642
6494
  }
6643
- const allItems = [...folders, ...files];
6644
6495
  if (allItems.length === 0) {
6645
6496
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow flex items-center justify-center text-text-disabled dark:text-text-disabled-dark", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
6646
6497
  /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-12 h-12 mx-auto mb-4 opacity-50", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1, d: "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" }) }),
6647
6498
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", children: "This folder is empty" }),
6648
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { className: "mt-3", onClick: () => setUploadDialogOpen(true), children: [
6649
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { size: ui.iconSize.smallest }),
6650
- "Upload files"
6499
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-3", children: [
6500
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "text", onClick: () => {
6501
+ setNewFolderName("");
6502
+ setNewFolderDialogOpen(true);
6503
+ }, children: [
6504
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderPlusIcon, { size: ui.iconSize.smallest }),
6505
+ "New folder"
6506
+ ] }),
6507
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: () => setUploadDialogOpen(true), children: [
6508
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { size: ui.iconSize.smallest }),
6509
+ "Upload files"
6510
+ ] })
6651
6511
  ] })
6652
6512
  ] }) });
6653
6513
  }
6654
6514
  if (viewMode === "list") {
6655
6515
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full", children: [
6656
6516
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: ui.cls("border-b text-left text-[10px] uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark", ui.defaultBorderMixin), children: [
6657
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-2 font-bold", children: "Name" }),
6517
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "pl-3 pr-0 py-2 w-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { size: "small", checked: allItems.length > 0 && selectedPaths.size === allItems.length, indeterminate: selectedPaths.size > 0 && selectedPaths.size < allItems.length, onCheckedChange: handleSelectAll }) }),
6518
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-2 py-2 font-bold", children: "Name" }),
6658
6519
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-2 font-bold w-24", children: "Type" }),
6659
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-2 font-bold w-24 text-right", children: "Size" })
6520
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-2 font-bold w-24 text-right", children: "Size" }),
6521
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-2 py-2 w-10" })
6660
6522
  ] }) }),
6661
6523
  /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
6662
- folders.map((folder) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "hover:bg-surface-100 dark:hover:bg-surface-950 cursor-pointer transition-colors border-b border-surface-100 dark:border-surface-950/50", onClick: () => handleNavigate(folder.fullPath), children: [
6663
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6664
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderIcon, { size: ui.iconSize.smallest, className: "text-amber-500 dark:text-amber-400 shrink-0" }),
6665
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-medium truncate", children: folder.name })
6666
- ] }) }),
6667
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark", children: "Folder" }) }),
6668
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark", children: "—" }) })
6669
- ] }, folder.fullPath)),
6524
+ folders.map((folder) => {
6525
+ const isChecked = selectedPaths.has(folder.fullPath);
6526
+ return /* @__PURE__ */ jsxRuntime.jsxs("tr", { "data-storage-item": true, className: ui.cls("cursor-pointer transition-colors border-b group", ui.defaultBorderMixin, isChecked ? "bg-primary/5 dark:bg-primary/10" : "hover:bg-surface-100 dark:hover:bg-surface-800"), onClick: (e_7) => handleItemClick(folder, e_7), onDoubleClick: () => handleItemDoubleClick(folder), children: [
6527
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "pl-3 pr-0 py-2.5", onClick: (e_8) => e_8.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { size: "small", checked: isChecked, onCheckedChange: () => {
6528
+ setSelectedPaths((prev_3) => {
6529
+ const next_3 = new Set(prev_3);
6530
+ if (next_3.has(folder.fullPath)) next_3.delete(folder.fullPath);
6531
+ else next_3.add(folder.fullPath);
6532
+ return next_3;
6533
+ });
6534
+ } }) }),
6535
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-2 py-2.5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6536
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderIcon, { size: ui.iconSize.smallest, className: "text-amber-500 dark:text-amber-400 shrink-0" }),
6537
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-medium truncate", children: folder.name })
6538
+ ] }) }),
6539
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark", children: "Folder" }) }),
6540
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark", children: "—" }) }),
6541
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-2 py-2.5" })
6542
+ ] }, folder.fullPath);
6543
+ }),
6670
6544
  files.map((file_2) => {
6671
6545
  const FileIconComp = getFileIcon(file_2.contentType);
6672
- const isSelected = selectedFile?.fullPath === file_2.fullPath;
6673
- return /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: ui.cls("cursor-pointer transition-colors border-b border-surface-100 dark:border-surface-950/50", isSelected ? "bg-primary/5 dark:bg-primary/10" : "hover:bg-surface-100 dark:hover:bg-surface-950"), onClick: () => handleSelectFile(file_2), children: [
6674
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6546
+ const isChecked_0 = selectedPaths.has(file_2.fullPath);
6547
+ return /* @__PURE__ */ jsxRuntime.jsxs("tr", { "data-storage-item": true, className: ui.cls("cursor-pointer transition-colors border-b group", ui.defaultBorderMixin, isChecked_0 ? "bg-primary/5 dark:bg-primary/10" : "hover:bg-surface-100 dark:hover:bg-surface-800"), onClick: (e_9) => handleItemClick(file_2, e_9), onDoubleClick: () => handleItemDoubleClick(file_2), children: [
6548
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "pl-3 pr-0 py-2.5", onClick: (e_10) => e_10.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { size: "small", checked: isChecked_0, onCheckedChange: () => {
6549
+ setSelectedPaths((prev_4) => {
6550
+ const next_4 = new Set(prev_4);
6551
+ if (next_4.has(file_2.fullPath)) next_4.delete(file_2.fullPath);
6552
+ else next_4.add(file_2.fullPath);
6553
+ return next_4;
6554
+ });
6555
+ } }) }),
6556
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-2 py-2.5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6675
6557
  /* @__PURE__ */ jsxRuntime.jsx(FileIconComp, { size: ui.iconSize.smallest, className: "text-surface-accent-400 shrink-0" }),
6676
6558
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] truncate", children: file_2.name })
6677
6559
  ] }) }),
6678
6560
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark", children: getExtension(file_2.name) || file_2.contentType?.split("/")[1]?.toUpperCase() || "—" }) }),
6679
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark font-mono text-[11px]", children: file_2.size !== void 0 ? formatFileSize(file_2.size) : "—" }) })
6561
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-2.5 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark font-mono text-[11px]", children: file_2.size !== void 0 ? formatFileSize(file_2.size) : "—" }) }),
6562
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-2 py-2.5", onClick: (e_11) => e_11.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "smallest", className: "opacity-0 group-hover:opacity-100 transition-opacity", onClick: () => handleDeleteFile(file_2), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2Icon, { size: 14 }) }) })
6680
6563
  ] }, file_2.fullPath);
6681
6564
  })
6682
6565
  ] })
@@ -6685,10 +6568,13 @@ return result;
6685
6568
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow overflow-auto p-4", children: [
6686
6569
  folders.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
6687
6570
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-[10px] uppercase tracking-wider font-bold text-text-disabled dark:text-text-disabled-dark mb-2 block", children: "Folders" }),
6688
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3", children: folders.map((folder_0) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("rounded-lg p-3 cursor-pointer transition-all duration-150 border", ui.defaultBorderMixin, "hover:bg-surface-100 dark:hover:bg-surface-950 hover:shadow-sm", "flex items-center gap-2"), onClick: () => handleNavigate(folder_0.fullPath), children: [
6689
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderIcon, { size: ui.iconSize.smallest, className: "text-amber-500 dark:text-amber-400 shrink-0" }),
6690
- /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-medium truncate", children: folder_0.name })
6691
- ] }, folder_0.fullPath)) })
6571
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]", children: folders.map((folder_0) => {
6572
+ const isChecked_1 = selectedPaths.has(folder_0.fullPath);
6573
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-storage-item": true, className: ui.cls("rounded-lg p-3 cursor-pointer border", "transition-colors duration-150", ui.defaultBorderMixin, "hover:bg-surface-100 dark:hover:bg-surface-800 hover:shadow-sm", "flex items-center gap-2", isChecked_1 && "ring-2 ring-primary bg-primary/5 dark:bg-primary/10"), onClick: (e_12) => handleItemClick(folder_0, e_12), onDoubleClick: () => handleItemDoubleClick(folder_0), children: [
6574
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderIcon, { size: ui.iconSize.smallest, className: "text-amber-500 dark:text-amber-400 shrink-0" }),
6575
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[13px] font-medium truncate", children: folder_0.name })
6576
+ ] }, folder_0.fullPath);
6577
+ }) })
6692
6578
  ] }),
6693
6579
  files.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6694
6580
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", className: "text-[10px] uppercase tracking-wider font-bold text-text-disabled dark:text-text-disabled-dark mb-2 block", children: [
@@ -6696,16 +6582,15 @@ return result;
6696
6582
  files.length,
6697
6583
  ")"
6698
6584
  ] }),
6699
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3", children: files.map((file_3) => {
6585
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]", children: files.map((file_3) => {
6700
6586
  const FileIconComp_0 = getFileIcon(file_3.contentType);
6701
6587
  const ext = getExtension(file_3.name)?.toLowerCase() || "";
6702
6588
  const isImage = file_3.contentType?.startsWith("image/") || ["jpg", "jpeg", "png", "gif", "webp", "svg"].includes(ext);
6703
- const isSelected_0 = selectedFile?.fullPath === file_3.fullPath;
6704
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("rounded-lg overflow-hidden cursor-pointer transition-all duration-150 border group", ui.defaultBorderMixin, "hover:shadow-md hover:-translate-y-0.5", isSelected_0 && "ring-2 ring-primary"), onClick: () => handleSelectFile(file_3), children: [
6705
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aspect-square relative overflow-hidden bg-surface-100 dark:bg-surface-950 flex items-center justify-center", children: [
6706
- isImage && file_3.downloadUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: file_3.downloadUrl, alt: file_3.name, className: "w-full h-full object-cover transition-transform duration-200 group-hover:scale-105", loading: "lazy" }) : /* @__PURE__ */ jsxRuntime.jsx(FileIconComp_0, { className: "text-surface-accent-400 dark:text-surface-accent-500 w-8 h-8" }),
6707
- getExtension(file_3.name) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-1.5 right-1.5 px-1.5 py-0.5 rounded text-[9px] font-bold uppercase bg-black/50 text-white backdrop-blur-sm", children: getExtension(file_3.name) }),
6708
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cls("absolute inset-0 bg-black/0 group-hover:bg-black/10", "transition-colors duration-200") })
6589
+ const isChecked_2 = selectedPaths.has(file_3.fullPath);
6590
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-storage-item": true, className: ui.cls("rounded-lg overflow-hidden cursor-pointer border", "transition-shadow duration-150", ui.defaultBorderMixin, "hover:shadow-md", isChecked_2 && "ring-2 ring-primary"), onClick: (e_13) => handleItemClick(file_3, e_13), onDoubleClick: () => handleItemDoubleClick(file_3), children: [
6591
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aspect-square relative overflow-hidden bg-surface-100 dark:bg-surface-800 flex items-center justify-center", children: [
6592
+ isImage && file_3.downloadUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: file_3.downloadUrl, alt: file_3.name, className: "w-full h-full object-cover", loading: "lazy" }) : /* @__PURE__ */ jsxRuntime.jsx(FileIconComp_0, { className: "text-surface-accent-400 dark:text-surface-accent-500 w-8 h-8" }),
6593
+ getExtension(file_3.name) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-1.5 right-1.5 px-1.5 py-0.5 rounded text-[9px] font-bold uppercase bg-black/50 text-white backdrop-blur-sm", children: getExtension(file_3.name) })
6709
6594
  ] }),
6710
6595
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2.5", children: [
6711
6596
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", className: "text-[12px] font-medium truncate text-surface-900 dark:text-white", children: file_3.name }),
@@ -6716,37 +6601,79 @@ return result;
6716
6601
  ] })
6717
6602
  ] });
6718
6603
  };
6719
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full bg-white dark:bg-surface-950 overflow-hidden text-text-primary dark:text-text-primary-dark", children: [
6720
- /* @__PURE__ */ jsxRuntime.jsx(ui.ResizablePanels, { orientation: "horizontal", panelSizePercent: sidebarSize, onPanelSizeChange: setSidebarSize, minPanelSizePx: 180, firstPanel: /* @__PURE__ */ jsxRuntime.jsx(StorageSidebar, { folders, currentPath, onNavigate: handleNavigate, loading }), secondPanel: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full", children: [
6604
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full bg-white dark:bg-surface-800 overflow-hidden text-text-primary dark:text-text-primary-dark", children: [
6605
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full", children: [
6721
6606
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow flex flex-col min-w-0 h-full", children: [
6722
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex items-center justify-between pr-2 border-b bg-white dark:bg-surface-950 shrink-0", ui.defaultBorderMixin), children: [
6607
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("flex items-center justify-between pr-2 border-b bg-white dark:bg-surface-800 shrink-0 h-10", ui.defaultBorderMixin), children: [
6723
6608
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 flex-grow overflow-hidden px-3 py-2", children: [
6724
6609
  currentPath && /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Go up", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: handleNavigateUp, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeftIcon, { size: ui.iconSize.smallest }) }) }),
6725
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5 overflow-x-auto no-scrollbar", children: segments.map((seg, i) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
6726
- i > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark mx-0.5", children: "/" }),
6727
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", size: "small", className: ui.cls("px-1.5 py-0.5 min-h-0 min-w-0 h-6 text-xs whitespace-nowrap normal-case font-normal", i === segments.length - 1 ? "text-text-primary dark:text-text-primary-dark font-medium" : "text-text-secondary dark:text-text-secondary-dark"), onClick: () => handleNavigate(seg.path), children: seg.label })
6610
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-0.5 overflow-x-auto no-scrollbar", children: segments.map((seg, i_3) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
6611
+ i_3 > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-disabled dark:text-text-disabled-dark mx-0.5", children: "/" }),
6612
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", size: "small", className: ui.cls("px-1.5 py-0.5 min-h-0 min-w-0 h-6 text-xs whitespace-nowrap normal-case font-normal", i_3 === segments.length - 1 ? "text-text-primary dark:text-text-primary-dark font-medium" : "text-text-secondary dark:text-text-secondary-dark"), onClick: () => handleNavigate(seg.path), children: seg.label })
6728
6613
  ] }, seg.path)) }),
6729
6614
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
6730
- !loading && /* @__PURE__ */ jsxRuntime.jsxs(ui.Chip, { size: "small", className: "shrink-0 text-[10px]", children: [
6615
+ selectedPaths.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [
6616
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "body2", className: "text-[13px] font-medium whitespace-nowrap", children: [
6617
+ selectedPaths.size,
6618
+ " selected"
6619
+ ] }),
6620
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "text", onClick: () => {
6621
+ setDeleteDialogTarget("selection");
6622
+ setDeleteDialogOpen(true);
6623
+ }, children: [
6624
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2Icon, { size: 14, className: "mr-1" }),
6625
+ "Delete"
6626
+ ] }),
6627
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "text", onClick: () => {
6628
+ setSelectedPaths(/* @__PURE__ */ new Set());
6629
+ setSelectedFile(null);
6630
+ setSelectedDownloadUrl(null);
6631
+ }, children: [
6632
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { size: 14, className: "mr-1" }),
6633
+ "Deselect"
6634
+ ] })
6635
+ ] }) : !loading ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Chip, { size: "small", className: "shrink-0 text-[10px]", children: [
6731
6636
  files.length,
6732
6637
  " file",
6733
6638
  files.length !== 1 ? "s" : "",
6734
6639
  folders.length > 0 ? `, ${folders.length} folder${folders.length !== 1 ? "s" : ""}` : ""
6735
- ] })
6640
+ ] }) : null
6736
6641
  ] }),
6737
6642
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center justify-end gap-1.5 pr-1", children: [
6738
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Grid view", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => setViewMode("grid"), className: ui.cls(viewMode === "grid" && "bg-surface-100 dark:bg-surface-950"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGridIcon, { size: ui.iconSize.smallest }) }) }),
6739
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "List view", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => setViewMode("list"), className: ui.cls(viewMode === "list" && "bg-surface-100 dark:bg-surface-950"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListIcon, { size: ui.iconSize.smallest }) }) }),
6740
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-px bg-surface-200 dark:bg-surface-950 mx-0.5" }),
6643
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Grid view", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => setViewMode("grid"), className: ui.cls(viewMode === "grid" && "bg-surface-100 dark:bg-surface-800"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGridIcon, { size: ui.iconSize.smallest }) }) }),
6644
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "List view", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => setViewMode("list"), className: ui.cls(viewMode === "list" && "bg-surface-100 dark:bg-surface-800"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListIcon, { size: ui.iconSize.smallest }) }) }),
6645
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cls("h-4 w-px mx-0.5", ui.defaultBorderMixin, "bg-surface-200 dark:bg-surface-700") }),
6741
6646
  /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Refresh", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: handleRefresh, disabled: loading, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCwIcon, { size: ui.iconSize.smallest }) }) }),
6647
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "New folder", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => {
6648
+ setNewFolderName("");
6649
+ setNewFolderDialogOpen(true);
6650
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderPlusIcon, { size: ui.iconSize.smallest }) }) }),
6742
6651
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", color: "primary", onClick: () => setUploadDialogOpen(true), children: [
6743
6652
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UploadCloudIcon, { size: ui.iconSize.smallest, className: "mr-1" }),
6744
6653
  "Upload"
6745
6654
  ] })
6746
6655
  ] })
6747
6656
  ] }),
6748
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow flex flex-col overflow-hidden min-h-0", children: renderContents() }),
6749
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("px-4 py-1.5 border-t bg-surface-50 dark:bg-surface-900 flex items-center justify-between shrink-0", ui.defaultBorderMixin), children: [
6657
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ...getDropRootProps(), className: "flex-grow flex flex-col overflow-hidden min-h-0 relative", onClick: (e_14) => {
6658
+ const target = e_14.target;
6659
+ if (!target.closest("[data-storage-item]") && selectedPaths.size > 0) {
6660
+ setSelectedPaths(/* @__PURE__ */ new Set());
6661
+ setSelectedFile(null);
6662
+ setSelectedDownloadUrl(null);
6663
+ }
6664
+ }, children: [
6665
+ /* @__PURE__ */ jsxRuntime.jsx("input", { ...getDropInputProps() }),
6666
+ renderContents(),
6667
+ isDragActive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-10 flex items-center justify-center bg-primary/5 dark:bg-primary/10 backdrop-blur-[2px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2 p-6 rounded-xl border-2 border-dashed border-primary bg-white/80 dark:bg-surface-900/80", children: [
6668
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UploadCloudIcon, { className: "w-10 h-10 text-primary" }),
6669
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle2", className: "text-primary font-semibold", children: "Drop files to upload" }),
6670
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", color: "secondary", children: [
6671
+ "to /",
6672
+ currentPath || "root"
6673
+ ] })
6674
+ ] }) })
6675
+ ] }),
6676
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("px-4 py-1.5 border-t bg-surface-50 dark:bg-surface-800 flex items-center justify-between shrink-0", ui.defaultBorderMixin), children: [
6750
6677
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 text-[11px]", children: [
6751
6678
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-disabled dark:text-text-disabled-dark font-bold uppercase tracking-tighter", children: "Path" }),
6752
6679
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-text-secondary dark:text-text-secondary-dark", children: [
@@ -6754,18 +6681,78 @@ return result;
6754
6681
  currentPath || ""
6755
6682
  ] })
6756
6683
  ] }),
6757
- selectedFile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[11px] text-text-secondary dark:text-text-secondary-dark", children: [
6684
+ selectedPaths.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[11px] text-text-secondary dark:text-text-secondary-dark", children: [
6685
+ selectedPaths.size,
6686
+ " item",
6687
+ selectedPaths.size !== 1 ? "s" : "",
6688
+ " selected"
6689
+ ] }) : selectedFile ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[11px] text-text-secondary dark:text-text-secondary-dark", children: [
6758
6690
  "Selected: ",
6759
6691
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: selectedFile.name })
6760
- ] })
6692
+ ] }) : null
6761
6693
  ] })
6762
6694
  ] }),
6763
6695
  selectedFile && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-80 lg:w-96 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(FilePreviewPanel, { file: selectedFile, downloadUrl: selectedDownloadUrl, onClose: () => {
6764
6696
  setSelectedFile(null);
6765
6697
  setSelectedDownloadUrl(null);
6766
6698
  }, onDelete: () => handleDeleteFile(selectedFile) }) })
6767
- ] }) }),
6768
- /* @__PURE__ */ jsxRuntime.jsx(UploadDialog, { open: uploadDialogOpen, currentPath, onClose: () => setUploadDialogOpen(false), onUpload: handleUpload })
6699
+ ] }),
6700
+ /* @__PURE__ */ jsxRuntime.jsx(UploadDialog, { open: uploadDialogOpen, currentPath, onClose: () => setUploadDialogOpen(false), onUpload: handleUpload }),
6701
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Dialog, { open: deleteDialogOpen, onOpenChange: (open) => {
6702
+ if (!open && !deleting) {
6703
+ setDeleteDialogOpen(false);
6704
+ setDeleteDialogTarget(null);
6705
+ }
6706
+ }, children: [
6707
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { children: [
6708
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle1", className: "font-semibold mb-2", children: deleteDialogTarget === "selection" ? `Delete ${selectedPaths.size} item${selectedPaths.size !== 1 ? "s" : ""}?` : deleteDialogTarget ? `Delete folder "${deleteDialogTarget.name}"?` : "Delete?" }),
6709
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", color: "secondary", children: deleteDialogTarget === "selection" ? "This will permanently delete all selected files and folders, including their contents. This action cannot be undone." : "This will permanently delete the folder and all of its contents. This action cannot be undone." })
6710
+ ] }),
6711
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogActions, { children: [
6712
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", onClick: () => {
6713
+ setDeleteDialogOpen(false);
6714
+ setDeleteDialogTarget(null);
6715
+ }, disabled: deleting, children: "Cancel" }),
6716
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.LoadingButton, { color: "error", loading: deleting, onClick: deleteDialogTarget === "selection" ? handleBulkDelete : handleConfirmDeleteFolder, children: [
6717
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2Icon, { size: 14, className: "mr-1" }),
6718
+ "Delete"
6719
+ ] })
6720
+ ] })
6721
+ ] }),
6722
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Dialog, { open: newFolderDialogOpen, onOpenChange: (open_0) => {
6723
+ if (!open_0 && !creatingFolder) {
6724
+ setNewFolderDialogOpen(false);
6725
+ setNewFolderName("");
6726
+ }
6727
+ }, children: [
6728
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { children: [
6729
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle1", className: "font-semibold mb-4", children: "New Folder" }),
6730
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { autoFocus: true, size: "small", label: "Folder name", value: newFolderName, onChange: (e_15) => setNewFolderName(e_15.target.value), onKeyDown: (e_16) => {
6731
+ if (e_16.key === "Enter" && newFolderName.trim()) {
6732
+ e_16.preventDefault();
6733
+ handleCreateFolder();
6734
+ }
6735
+ }, disabled: creatingFolder, placeholder: "Enter folder name" }),
6736
+ currentPath && /* @__PURE__ */ jsxRuntime.jsxs(ui.Typography, { variant: "caption", color: "secondary", className: "mt-2", children: [
6737
+ "Will be created in ",
6738
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
6739
+ "/",
6740
+ currentPath,
6741
+ "/"
6742
+ ] })
6743
+ ] })
6744
+ ] }),
6745
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogActions, { children: [
6746
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "text", onClick: () => {
6747
+ setNewFolderDialogOpen(false);
6748
+ setNewFolderName("");
6749
+ }, disabled: creatingFolder, children: "Cancel" }),
6750
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.LoadingButton, { color: "primary", loading: creatingFolder, disabled: !newFolderName.trim(), onClick: handleCreateFolder, children: [
6751
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderPlusIcon, { size: 14, className: "mr-1" }),
6752
+ "Create"
6753
+ ] })
6754
+ ] })
6755
+ ] })
6769
6756
  ] });
6770
6757
  };
6771
6758
  const StorageView$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -8127,7 +8114,7 @@ return result;
8127
8114
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "font-bold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark", children: "Tables" }),
8128
8115
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-[10px] text-text-disabled dark:text-text-disabled-dark font-mono", children: stats.tables })
8129
8116
  ] }),
8130
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1.5 border-b border-surface-200/40 dark:border-surface-700/40", children: /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { size: "smallest", placeholder: "Filter tables…", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), inputClassName: "text-xs" }) }),
8117
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1.5 border-b border-surface-200/40 dark:border-surface-700/40", children: /* @__PURE__ */ jsxRuntime.jsx(ui.SearchBar, { size: "smallest", placeholder: "Filter tables…", onTextSearch: (val) => setSearchQuery(val ?? ""), innerClassName: "text-xs" }) }),
8131
8118
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-grow overflow-y-auto no-scrollbar p-1", children: [
8132
8119
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: filteredCollections.map((collection) => {
8133
8120
  const table = collection.table ?? collection.slug;
@@ -8183,8 +8170,8 @@ return result;
8183
8170
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 px-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "subtitle2", className: "font-mono text-text-secondary dark:text-text-secondary-dark", children: "Schema Visualizer" }) }),
8184
8171
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [
8185
8172
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center bg-surface-100 dark:bg-surface-950 rounded-md border border-surface-200/40 dark:border-surface-700/40", children: [
8186
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Left to right layout", children: /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setDirection("LR"), className: ui.cls("px-2 py-1 text-[10px] font-mono rounded-l-md transition-colors", direction === "LR" ? "bg-primary text-white" : "text-text-secondary dark:text-text-secondary-dark hover:bg-surface-200 dark:hover:bg-surface-700"), children: "LR" }) }),
8187
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Top to bottom layout", children: /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setDirection("TB"), className: ui.cls("px-2 py-1 text-[10px] font-mono rounded-r-md transition-colors", direction === "TB" ? "bg-primary text-white" : "text-text-secondary dark:text-text-secondary-dark hover:bg-surface-200 dark:hover:bg-surface-700"), children: "TB" }) })
8173
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Left to right layout", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: direction === "LR" ? "filled" : "text", color: direction === "LR" ? "primary" : "neutral", onClick: () => setDirection("LR"), className: "!rounded-r-none !px-2 !py-1 !text-[10px] !font-mono", children: "LR" }) }),
8174
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Top to bottom layout", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: direction === "TB" ? "filled" : "text", color: direction === "TB" ? "primary" : "neutral", onClick: () => setDirection("TB"), className: "!rounded-l-none !px-2 !py-1 !text-[10px] !font-mono", children: "TB" }) })
8188
8175
  ] }),
8189
8176
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-px bg-surface-200 dark:bg-surface-950 mx-0.5" }),
8190
8177
  /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Fit to view", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: handleFitView, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" }) }) }) }),
@@ -9212,10 +9199,10 @@ return result;
9212
9199
  } }),
9213
9200
  hasBody && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9214
9201
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-text-secondary dark:text-text-secondary-dark text-xs font-semibold uppercase tracking-wider mb-2 block", children: "Request Body" }),
9215
- /* @__PURE__ */ jsxRuntime.jsx("textarea", { value: body, onChange: (e) => {
9202
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { multiline: true, minRows: 10, value: body, onChange: (e) => {
9216
9203
  setBody(e.target.value);
9217
9204
  setValidationError(null);
9218
- }, rows: 10, spellCheck: false, className: ui.cls("w-full font-mono text-xs p-3 rounded-lg resize-y", "bg-surface-50 dark:bg-surface-900", validationError ? "border-red-500 focus:ring-red-500/30" : ui.cls("border focus:ring-primary/30 dark:focus:ring-primary-dark/30", ui.defaultBorderMixin), "text-text-primary dark:text-text-primary-dark", "focus:outline-none focus:ring-2", "transition-all") }),
9205
+ }, spellCheck: false, error: !!validationError, className: "w-full", inputClassName: "font-mono text-xs p-3 resize-y" }),
9219
9206
  validationError && /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "text-red-500 mt-1 block text-xs", children: validationError })
9220
9207
  ] }),
9221
9208
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-surface-100 dark:bg-surface-900 p-3", children: [
@@ -9269,7 +9256,7 @@ return result;
9269
9256
  /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-xs font-mono font-semibold", children: p.name }),
9270
9257
  p.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-0.5 text-xs", children: "*" })
9271
9258
  ] }),
9272
- /* @__PURE__ */ jsxRuntime.jsx("input", { type: "text", placeholder: p.description ?? p.name, value: values[p.name] ?? "", onChange: (e) => onChange(p.name, e.target.value), className: ui.cls("flex-1 px-3 py-1.5 text-xs rounded-lg font-mono", "bg-surface-50 dark:bg-surface-900", "border", ui.defaultBorderMixin, "text-text-primary dark:text-text-primary-dark", "placeholder:text-text-secondary/50", "focus:outline-none focus:ring-2 focus:ring-primary/30", "transition-all") })
9259
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { size: "small", placeholder: p.description ?? p.name, value: values[p.name] ?? "", onChange: (e) => onChange(p.name, e.target.value), className: "flex-1", inputClassName: "font-mono text-xs" })
9273
9260
  ] }, p.name);
9274
9261
  $[6] = onChange;
9275
9262
  $[7] = values;
@@ -9333,7 +9320,7 @@ return result;
9333
9320
  }
9334
9321
  let t3;
9335
9322
  if ($[3] !== onAdd) {
9336
- t3 = /* @__PURE__ */ jsxRuntime.jsxs("button", { onClick: onAdd, className: "text-xs text-primary dark:text-primary-dark hover:underline flex items-center gap-1 font-medium", children: [
9323
+ t3 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "text", size: "small", color: "primary", onClick: onAdd, className: "text-xs p-0 min-h-0", children: [
9337
9324
  t2,
9338
9325
  " Add Header"
9339
9326
  ] });
@@ -9359,9 +9346,9 @@ return result;
9359
9346
  let t62;
9360
9347
  if ($[12] !== onChange || $[13] !== onRemove) {
9361
9348
  t62 = (v, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9362
- /* @__PURE__ */ jsxRuntime.jsx("input", { type: "text", placeholder: "Header name", value: v.key, onChange: (e) => onChange(i, e.target.value, v.value), className: ui.cls("w-1/3 px-3 py-1.5 text-xs rounded-lg font-mono", "bg-surface-50 dark:bg-surface-900", "border", ui.defaultBorderMixin, "text-text-primary dark:text-text-primary-dark", "placeholder:text-text-secondary/50", "focus:outline-none focus:ring-2 focus:ring-primary/30", "transition-all") }),
9363
- /* @__PURE__ */ jsxRuntime.jsx("input", { type: "text", placeholder: "Value", value: v.value, onChange: (e_0) => onChange(i, v.key, e_0.target.value), className: ui.cls("flex-1 px-3 py-1.5 text-xs rounded-lg font-mono", "bg-surface-50 dark:bg-surface-900", "border", ui.defaultBorderMixin, "text-text-primary dark:text-text-primary-dark", "placeholder:text-text-secondary/50", "focus:outline-none focus:ring-2 focus:ring-primary/30", "transition-all") }),
9364
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => onRemove(i), className: "p-1.5 text-text-secondary hover:text-red-500 rounded transition-colors flex items-center justify-center shrink-0", title: "Remove", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { size: ui.iconSize.small }) })
9349
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { size: "small", placeholder: "Header name", value: v.key, onChange: (e) => onChange(i, e.target.value, v.value), className: "w-1/3", inputClassName: "font-mono text-xs" }),
9350
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { size: "small", placeholder: "Value", value: v.value, onChange: (e_0) => onChange(i, v.key, e_0.target.value), className: "flex-1", inputClassName: "font-mono text-xs" }),
9351
+ /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: () => onRemove(i), className: "text-text-secondary hover:text-red-500 shrink-0", title: "Remove", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { size: ui.iconSize.small }) })
9365
9352
  ] }, i);
9366
9353
  $[12] = onChange;
9367
9354
  $[13] = onRemove;
@@ -9573,17 +9560,17 @@ return result;
9573
9560
  "v",
9574
9561
  spec.info.version
9575
9562
  ] }),
9576
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(ui.SearchBar, { placeholder: "Filter endpoints…", size: "small", onTextSearch: (val) => setSidebarFilter(val || "") }) })
9563
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(ui.SearchBar, { placeholder: "Filter endpoints…", size: "small", onTextSearch: (val) => setSidebarFilter(val ?? "") }) })
9577
9564
  ] }),
9578
9565
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto px-2 pb-4", children: [
9579
9566
  filteredGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3", children: [
9580
9567
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "px-2 py-1.5 text-text-secondary dark:text-text-secondary-dark uppercase tracking-wider font-semibold text-[10px]", children: group.tag }),
9581
9568
  group.endpoints.map((ep) => {
9582
9569
  const isSelected = selectedEndpoint?.id === ep.id;
9583
- return /* @__PURE__ */ jsxRuntime.jsxs("button", { onClick: () => {
9570
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "text", color: "neutral", fullWidth: true, onClick: () => {
9584
9571
  setSelectedEndpoint(ep);
9585
9572
  setTryItOpen(false);
9586
- }, className: ui.cls("w-full flex items-center justify-between gap-2 px-2.5 py-1.5 rounded-lg text-left text-sm transition-all", "hover:bg-surface-200 dark:hover:bg-surface-800", isSelected ? "bg-surface-200 dark:bg-surface-800 font-medium" : "text-text-primary dark:text-text-primary-dark"), children: [
9573
+ }, className: ui.cls("!justify-between !px-2.5 !py-1.5 !text-left !text-sm", isSelected ? "bg-surface-200 dark:bg-surface-800 font-medium" : "text-text-primary dark:text-text-primary-dark"), children: [
9587
9574
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[13px] opacity-90", children: ep.summary || ep.shortPath }),
9588
9575
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cls("text-[10px] font-bold uppercase shrink-0", METHOD_COLORS[ep.method] ?? "text-text-secondary"), children: ep.method })
9589
9576
  ] }, ep.id);