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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +4 -4
  2. package/dist/{ApiExplorer-CdIwR9Ga.js → ApiExplorer-B9M9-uy_.js} +3 -3
  3. package/dist/ApiExplorer-B9M9-uy_.js.map +1 -0
  4. package/dist/{ApiKeysView-D-_FSlNL.js → ApiKeysView-vQKqt2wl.js} +45 -3
  5. package/dist/ApiKeysView-vQKqt2wl.js.map +1 -0
  6. package/dist/{AuthSimulationSelector-iEZ-Or_1.js → AuthSimulationSelector-Bougd521.js} +2 -2
  7. package/dist/AuthSimulationSelector-Bougd521.js.map +1 -0
  8. package/dist/BackupsView-DNS6LdVg.js +227 -0
  9. package/dist/BackupsView-DNS6LdVg.js.map +1 -0
  10. package/dist/{BranchesView-Dlg78EQ8.js → BranchesView-DH0qnU9J.js} +2 -2
  11. package/dist/BranchesView-DH0qnU9J.js.map +1 -0
  12. package/dist/{CronJobsView-4gdtJvoe.js → CronJobsView-B59i3Mis.js} +2 -2
  13. package/dist/CronJobsView-B59i3Mis.js.map +1 -0
  14. package/dist/{JSEditor-Ca4XYGRp.js → JSEditor-BeHHuxhA.js} +28 -32
  15. package/dist/JSEditor-BeHHuxhA.js.map +1 -0
  16. package/dist/LogsExplorer-BCXoGREr.js +298 -0
  17. package/dist/LogsExplorer-BCXoGREr.js.map +1 -0
  18. package/dist/{MonacoEditor-COZqrIJ1.js → MonacoEditor-D0_QljcX.js} +2 -2
  19. package/dist/MonacoEditor-D0_QljcX.js.map +1 -0
  20. package/dist/{RLSEditor-BM64laoW.js → RLSEditor-D6adwB6e.js} +38 -34
  21. package/dist/RLSEditor-D6adwB6e.js.map +1 -0
  22. package/dist/{SQLEditor-CuAhR-zr.js → SQLEditor-_dCqVAN_.js} +8 -8
  23. package/dist/SQLEditor-_dCqVAN_.js.map +1 -0
  24. package/dist/{SchemaVisualizer-OibKoD3g.js → SchemaVisualizer-C_ErehfH.js} +11 -11
  25. package/dist/SchemaVisualizer-C_ErehfH.js.map +1 -0
  26. package/dist/{StorageView-BMhD29YO.js → StorageView-UvyM2xdW.js} +2 -2
  27. package/dist/StorageView-UvyM2xdW.js.map +1 -0
  28. package/dist/components/AuthSimulationSelector.d.ts +1 -1
  29. package/dist/components/Backups/BackupsView.d.ts +2 -0
  30. package/dist/components/SchemaVisualizer/useSchemaGraph.d.ts +2 -2
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.es.js +74 -111
  33. package/dist/index.es.js.map +1 -1
  34. package/dist/utils/pgColumnToProperty.d.ts +3 -3
  35. package/dist/utils/sql_utils.d.ts +3 -3
  36. package/package.json +11 -12
  37. package/src/components/ApiExplorer/ApiExplorer.tsx +1 -1
  38. package/src/components/ApiExplorer/TryItPanel.tsx +1 -1
  39. package/src/components/ApiKeys/ApiKeysView.tsx +43 -3
  40. package/src/components/AuthSimulationSelector.tsx +1 -1
  41. package/src/components/Backups/BackupsView.tsx +185 -0
  42. package/src/components/Branches/BranchesView.tsx +1 -1
  43. package/src/components/CronJobs/CronJobsView.tsx +1 -1
  44. package/src/components/JSEditor/JSEditor.tsx +12 -12
  45. package/src/components/JSEditor/JSMonacoEditor.tsx +21 -25
  46. package/src/components/LogsExplorer/LogsExplorer.tsx +168 -46
  47. package/src/components/RLSEditor/PolicyEditor.tsx +5 -3
  48. package/src/components/RLSEditor/RLSEditor.tsx +51 -34
  49. package/src/components/RebaseStudio.tsx +12 -3
  50. package/src/components/SQLEditor/MonacoEditor.tsx +1 -1
  51. package/src/components/SQLEditor/SQLEditor.tsx +6 -6
  52. package/src/components/SQLEditor/SQLEditorSidebar.tsx +1 -1
  53. package/src/components/SQLEditor/SchemaBrowser.tsx +3 -3
  54. package/src/components/SchemaVisualizer/SchemaVisualizer.tsx +10 -9
  55. package/src/components/SchemaVisualizer/TableNode.tsx +1 -1
  56. package/src/components/SchemaVisualizer/useSchemaGraph.ts +11 -11
  57. package/src/components/StorageView/StorageView.tsx +1 -1
  58. package/src/components/StudioHomePage.tsx +62 -87
  59. package/src/index.ts +4 -4
  60. package/src/utils/pgColumnToProperty.ts +3 -3
  61. package/src/utils/sql_utils.test.ts +6 -6
  62. package/src/utils/sql_utils.ts +3 -3
  63. package/dist/ApiExplorer-CdIwR9Ga.js.map +0 -1
  64. package/dist/ApiKeysView-D-_FSlNL.js.map +0 -1
  65. package/dist/AuthSimulationSelector-iEZ-Or_1.js.map +0 -1
  66. package/dist/BranchesView-Dlg78EQ8.js.map +0 -1
  67. package/dist/CronJobsView-4gdtJvoe.js.map +0 -1
  68. package/dist/JSEditor-Ca4XYGRp.js.map +0 -1
  69. package/dist/LogsExplorer-J4xfsuv3.js +0 -206
  70. package/dist/LogsExplorer-J4xfsuv3.js.map +0 -1
  71. package/dist/MonacoEditor-COZqrIJ1.js.map +0 -1
  72. package/dist/RLSEditor-BM64laoW.js.map +0 -1
  73. package/dist/SQLEditor-CuAhR-zr.js.map +0 -1
  74. package/dist/SchemaVisualizer-OibKoD3g.js.map +0 -1
  75. package/dist/StorageView-BMhD29YO.js.map +0 -1
  76. package/dist/index.umd.js +0 -11491
  77. package/dist/index.umd.js.map +0 -1
  78. package/src/vite-env.d.ts +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogsExplorer-BCXoGREr.js","names":[],"sources":["../src/components/LogsExplorer/LogsExplorer.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { ArrowDownToLineIcon, Checkbox, cls, defaultBorderMixin, Label, Select, SelectItem, TextField, Typography } from \"@rebasepro/ui\";\nimport { useApiConfig } from \"@rebasepro/app\";\n\ninterface LogEntry {\n id: string;\n timestamp: string;\n level: \"debug\" | \"info\" | \"warn\" | \"error\";\n source: \"api\" | \"auth\" | \"storage\" | \"realtime\" | \"system\";\n message: string;\n metadata?: Record<string, unknown>;\n}\n\nconst LEVEL_COLORS: Record<string, string> = {\n debug: \"text-surface-500\",\n info: \"text-blue-600 dark:text-blue-500\",\n warn: \"text-amber-600 dark:text-amber-500\",\n error: \"text-red-600 dark:text-red-500\"\n};\n\nconst SOURCE_COLORS: Record<string, string> = {\n api: \"text-sky-600 dark:text-sky-400\",\n auth: \"text-purple-600 dark:text-purple-400\",\n storage: \"text-green-600 dark:text-green-500\",\n realtime: \"text-orange-600 dark:text-orange-400\",\n system: \"text-surface-600 dark:text-surface-400\"\n};\n\n// Ids are `log_<n>` with a monotonic counter, so numeric comparison tells\n// old entries from new ones across polls.\nconst idNum = (entry: LogEntry): number => Number(entry.id.slice(\"log_\".length));\n\n// The window is contiguous and ordered, so identical ends mean identical content.\nconst sameLogs = (a: LogEntry[], b: LogEntry[]): boolean =>\n a.length === b.length &&\n a[0]?.id === b[0]?.id &&\n a[a.length - 1]?.id === b[b.length - 1]?.id;\n\n// How close to the bottom edge still counts as \"at the bottom\".\nconst STICK_THRESHOLD = 40;\n\nexport function LogsExplorer() {\n const [logs, setLogs] = useState<LogEntry[]>([]);\n const [level, setLevel] = useState<string>(\"all\");\n const [source, setSource] = useState<string>(\"all\");\n const [searchInput, setSearchInput] = useState(\"\");\n const [search, setSearch] = useState(\"\");\n const [autoScroll, setAutoScroll] = useState(true);\n const [error, setError] = useState<string | null>(null);\n // Entries that arrived while the user was scrolled away from the bottom.\n const [newCount, setNewCount] = useState(0);\n const [atBottom, setAtBottom] = useState(true);\n const containerRef = useRef<HTMLDivElement>(null);\n // Whether the view is stuck to the bottom right now. A ref, not state:\n // the scroll handler and the fetch loop both read it synchronously.\n const stickRef = useRef(true);\n const lastMaxIdRef = useRef<number | null>(null);\n const apiConfig = useApiConfig();\n\n // Debounce the search box so typing doesn't refetch per keystroke.\n useEffect(() => {\n const t = setTimeout(() => setSearch(searchInput), 300);\n return () => clearTimeout(t);\n }, [searchInput]);\n\n const fetchLogs = useCallback(async () => {\n if (!apiConfig?.apiUrl) {\n setError(\"No API URL configured — cannot load logs.\");\n return;\n }\n try {\n const params = new URLSearchParams();\n if (level && level !== \"all\") params.set(\"level\", level);\n if (source && source !== \"all\") params.set(\"source\", source);\n if (search) params.set(\"search\", search);\n params.set(\"limit\", \"200\");\n\n // Logs are admin-only, so the request must carry the auth token. The\n // URL is absolute: a relative one would resolve against the frontend\n // origin, which serves index.html rather than the API.\n const headers: Record<string, string> = {};\n const token = apiConfig.getAuthToken ? await apiConfig.getAuthToken() : null;\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n\n const resp = await fetch(`${apiConfig.apiUrl}/api/logs?${params}`, { headers });\n if (!resp.ok) {\n setError(resp.status === 401 || resp.status === 403\n ? \"Not authorised to read logs — an admin role is required.\"\n : `Could not load logs (HTTP ${resp.status}).`);\n return;\n }\n const data: { entries?: LogEntry[] } = await resp.json();\n // The API returns newest-first; the view tails like a terminal, so\n // flip to chronological order (newest at the bottom).\n const entries = (data.entries || []).slice().reverse();\n\n const prevMax = lastMaxIdRef.current;\n if (prevMax != null && !stickRef.current) {\n const fresh = entries.filter(e => idNum(e) > prevMax).length;\n if (fresh > 0) setNewCount(c => c + fresh);\n }\n if (entries.length > 0) lastMaxIdRef.current = idNum(entries[entries.length - 1]);\n\n // Unchanged window → keep the previous array so React leaves the\n // DOM alone (hover states and text selection survive the poll).\n setLogs(prev => sameLogs(prev, entries) ? prev : entries);\n setError(null);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Could not load logs.\");\n }\n }, [level, source, search, apiConfig]);\n\n // A filter change replaces the window wholesale — \"new entries since last\n // poll\" stops meaning anything, so the counter starts over.\n useEffect(() => {\n lastMaxIdRef.current = null;\n setNewCount(0);\n }, [level, source, search]);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let cancelled = false;\n\n fetchLogs();\n\n const scheduleNext = () => {\n if (cancelled) return;\n timeoutId = setTimeout(async () => {\n if (document.visibilityState === \"visible\") {\n await fetchLogs();\n }\n scheduleNext();\n }, 3000);\n };\n\n scheduleNext();\n\n const handleVisibility = () => {\n if (document.visibilityState === \"visible\") {\n fetchLogs();\n }\n };\n document.addEventListener(\"visibilitychange\", handleVisibility);\n\n return () => {\n cancelled = true;\n if (timeoutId) clearTimeout(timeoutId);\n document.removeEventListener(\"visibilitychange\", handleVisibility);\n };\n }, [fetchLogs]);\n\n const scrollToBottom = useCallback(() => {\n const el = containerRef.current;\n if (!el) return;\n el.scrollTop = el.scrollHeight;\n stickRef.current = true;\n setAtBottom(true);\n setNewCount(0);\n }, []);\n\n // Stick to the bottom only while the user is already there. Scrolling up\n // disengages; scrolling back down re-engages. Our own scrollTop writes\n // always land at the bottom, so they can never disengage it.\n const handleScroll = useCallback(() => {\n const el = containerRef.current;\n if (!el) return;\n const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < STICK_THRESHOLD;\n stickRef.current = nearBottom;\n setAtBottom(nearBottom);\n if (nearBottom) setNewCount(0);\n }, []);\n\n useLayoutEffect(() => {\n if (autoScroll && stickRef.current) {\n const el = containerRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n }\n }, [logs, autoScroll]);\n\n return (\n <div className=\"flex flex-col h-[calc(100vh-64px)] w-full bg-surface-50 dark:bg-surface-800\">\n {/* Toolbar */}\n <div className={cls(\n \"flex gap-2 p-3 border-b items-center flex-wrap shrink-0\",\n defaultBorderMixin\n )}>\n <Select\n value={level}\n onValueChange={setLevel}\n size=\"small\"\n placeholder=\"All Levels\"\n >\n <SelectItem value=\"all\">All Levels</SelectItem>\n <SelectItem value=\"debug\">Debug</SelectItem>\n <SelectItem value=\"info\">Info</SelectItem>\n <SelectItem value=\"warn\">Warn</SelectItem>\n <SelectItem value=\"error\">Error</SelectItem>\n </Select>\n <Select\n value={source}\n onValueChange={setSource}\n size=\"small\"\n placeholder=\"All Sources\"\n >\n <SelectItem value=\"all\">All Sources</SelectItem>\n <SelectItem value=\"api\">API</SelectItem>\n <SelectItem value=\"auth\">Auth</SelectItem>\n <SelectItem value=\"storage\">Storage</SelectItem>\n <SelectItem value=\"realtime\">Realtime</SelectItem>\n <SelectItem value=\"system\">System</SelectItem>\n </Select>\n <TextField\n size=\"small\"\n placeholder=\"Search logs...\"\n value={searchInput}\n onChange={e => setSearchInput(e.target.value)}\n className=\"flex-1 min-w-[200px]\"\n />\n <div className=\"flex items-center gap-1.5 cursor-pointer ml-2\">\n <Checkbox\n id=\"auto-scroll\"\n checked={autoScroll}\n onCheckedChange={(checked: boolean) => {\n setAutoScroll(checked);\n if (checked) scrollToBottom();\n }}\n size=\"small\"\n padding={false}\n />\n <Label\n htmlFor=\"auto-scroll\"\n className=\"text-xs select-none cursor-pointer text-surface-600 dark:text-surface-400\"\n >\n Auto-scroll\n </Label>\n </div>\n <div className=\"ml-auto pl-4\">\n <Typography variant=\"caption\" color=\"secondary\">\n {logs.length} entries\n </Typography>\n </div>\n </div>\n\n {/* A failing poll must stay visible even while stale logs are on\n screen — otherwise the view quietly freezes. */}\n {error && logs.length > 0 && (\n <div className={cls(\n \"px-4 py-1.5 border-b bg-amber-50 dark:bg-amber-950/20 shrink-0\",\n defaultBorderMixin\n )}>\n <Typography variant=\"caption\" className=\"text-amber-700 dark:text-amber-400\">\n {error}\n </Typography>\n </div>\n )}\n\n {/* Log entries */}\n <div className=\"relative flex-1 min-h-0\">\n <div\n ref={containerRef}\n onScroll={handleScroll}\n className=\"h-full overflow-auto py-2\"\n >\n {logs.map(log => (\n <div\n key={log.id}\n className={cls(\n \"flex gap-4 px-4 py-[6px] border-b hover:bg-surface-100 dark:hover:bg-surface-900 transition-colors\",\n defaultBorderMixin\n )}\n >\n <Typography variant=\"body2\" color=\"secondary\" className=\"w-[72px] shrink-0 font-mono\">\n {new Date(log.timestamp).toLocaleTimeString()}\n </Typography>\n <Typography variant=\"body2\" className={cls(\"w-[48px] shrink-0 uppercase font-semibold font-mono\", LEVEL_COLORS[log.level] || \"text-surface-500\")}>\n {log.level}\n </Typography>\n <Typography variant=\"body2\" className={cls(\"w-[80px] shrink-0 font-mono\", SOURCE_COLORS[log.source] || \"text-surface-500\")}>\n [{log.source}]\n </Typography>\n <Typography variant=\"body2\" className=\"flex-1 font-mono break-all whitespace-pre-wrap text-surface-900 dark:text-surface-100\">\n {log.message}\n </Typography>\n </div>\n ))}\n {logs.length === 0 && (\n <div className=\"p-8 text-center\">\n <Typography\n variant=\"body2\"\n className={error ? \"text-red-600 dark:text-red-500\" : undefined}\n color={error ? undefined : \"secondary\"}\n >\n {error ?? \"No log entries yet. Logs will appear here as requests come in.\"}\n </Typography>\n </div>\n )}\n </div>\n\n {autoScroll && !atBottom && newCount > 0 && (\n <button\n onClick={scrollToBottom}\n className=\"absolute bottom-3 left-1/2 -translate-x-1/2 flex items-center gap-1.5 rounded-full bg-primary text-white text-xs font-medium pl-2.5 pr-3 py-1.5 shadow-md hover:bg-primary-dark transition-colors\"\n >\n <ArrowDownToLineIcon size={14}/>\n {newCount} new {newCount === 1 ? \"entry\" : \"entries\"}\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { useModeController } from "@rebasepro/core";
1
+ import { useModeController } from "@rebasepro/app";
2
2
  import { useRef } from "react";
3
3
  import { cls } from "@rebasepro/ui";
4
4
  import { jsx } from "react/jsx-runtime";
@@ -243,4 +243,4 @@ var MonacoEditor = ({ value, onChange, onRun, className, readOnly = false, autoF
243
243
  //#endregion
244
244
  export { MonacoEditor as t };
245
245
 
246
- //# sourceMappingURL=MonacoEditor-COZqrIJ1.js.map
246
+ //# sourceMappingURL=MonacoEditor-D0_QljcX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonacoEditor-D0_QljcX.js","names":[],"sources":["../src/components/SQLEditor/MonacoEditor.tsx"],"sourcesContent":["import React, { useRef } from \"react\";\nimport Editor, { Monaco, OnMount } from \"@monaco-editor/react\";\nimport type { editor, Position, IRange } from \"monaco-editor\";\nimport { cls, defaultBorderMixin } from \"@rebasepro/ui\";\nimport { useModeController } from \"@rebasepro/app\";\n\nexport type MonacoEditorProps = {\n value: string;\n onChange: (value: string | undefined) => void;\n onRun?: (selectedText?: string) => void;\n className?: string;\n readOnly?: boolean;\n autoFocus?: boolean;\n schemas?: Record<string, { schemaName: string, tableName: string, columns: { name: string, dataType: string }[] }[]>;\n};\n\nexport const MonacoEditor = ({\n value,\n onChange,\n onRun,\n className,\n readOnly = false,\n autoFocus = true,\n schemas\n}: MonacoEditorProps) => {\n const { mode } = useModeController();\n const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);\n const monacoRef = useRef<Monaco | null>(null);\n const onRunRef = useRef(onRun);\n onRunRef.current = onRun;\n\n const schemasRef = useRef(schemas);\n schemasRef.current = schemas;\n\n const handleEditorOnMount: OnMount = (editor, monaco) => {\n editorRef.current = editor;\n monacoRef.current = monaco;\n\n editor.addAction({\n id: \"run-query\",\n label: \"Run Query\",\n keybindings: [monaco.KeyMod.CtrlCmd + monaco.KeyCode.Enter],\n contextMenuGroupId: \"operation\",\n contextMenuOrder: 0,\n run: () => {\n if (onRunRef.current) {\n const selection = editor.getSelection();\n let selectedText: string | undefined = undefined;\n if (selection && !selection.isEmpty()) {\n selectedText = editor.getModel()?.getValueInRange(selection)?.trim();\n }\n onRunRef.current(selectedText || undefined);\n }\n }\n });\n\n // Register custom autocomplete for tables, columns, and SQL keywords\n const sqlKeywords = [\n \"SELECT\", \"FROM\", \"WHERE\", \"INSERT INTO\", \"VALUES\", \"UPDATE\", \"SET\",\n \"DELETE FROM\", \"JOIN\", \"INNER JOIN\", \"LEFT JOIN\", \"RIGHT JOIN\", \"FULL JOIN\",\n \"ON\", \"GROUP BY\", \"HAVING\", \"ORDER BY\", \"ASC\", \"DESC\", \"LIMIT\", \"OFFSET\",\n \"AS\", \"AND\", \"OR\", \"NOT\", \"IN\", \"BETWEEN\", \"LIKE\", \"IS NULL\", \"IS NOT NULL\",\n \"CREATE TABLE\", \"ALTER TABLE\", \"DROP TABLE\", \"PRIMARY KEY\", \"FOREIGN KEY\",\n \"COUNT\", \"SUM\", \"AVG\", \"MIN\", \"MAX\", \"DISTINCT\", \"UNION\", \"ALL\", \"EXISTS\",\n \"CASE\", \"WHEN\", \"THEN\", \"ELSE\", \"END\", \"CAST\", \"COALESCE\"\n ];\n\n monaco.languages.registerCompletionItemProvider(\"pgsql\", {\n triggerCharacters: [\".\", \" \", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\"],\n provideCompletionItems: (model: editor.ITextModel, position: Position) => {\n const word = model.getWordUntilPosition(position);\n const range = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: word.startColumn,\n endColumn: word.endColumn\n };\n\n const textUntilPosition = model.getValueInRange({\n startLineNumber: position.lineNumber,\n startColumn: 1,\n endLineNumber: position.lineNumber,\n endColumn: position.column\n });\n\n // Check if user is typing `tableName.`\n const match = textUntilPosition.match(/([a-zA-Z0-9_]+)\\.$/);\n const tableNameMatch = match ? match[1] : null;\n\n const suggestions: { label: string; kind: number; insertText: string; range: IRange; detail: string; sortText: string }[] = [];\n const allSchemas = schemasRef.current || {};\n\n if (tableNameMatch) {\n // Provide columns for the matched table\n for (const [, tables] of Object.entries(allSchemas)) {\n const table = tables.find(t => t.tableName === tableNameMatch);\n if (table) {\n table.columns.forEach(col => {\n suggestions.push({\n label: col.name,\n kind: monaco.languages.CompletionItemKind.Field,\n insertText: col.name,\n range,\n detail: \"Column\",\n sortText: \"1\"\n });\n });\n }\n }\n } else {\n // Provide table names\n for (const [sName, tables] of Object.entries(allSchemas)) {\n tables.forEach(table => {\n suggestions.push({\n label: table.tableName,\n kind: monaco.languages.CompletionItemKind.Class,\n insertText: table.tableName,\n range,\n detail: `Table (${sName})`,\n sortText: \"2\"\n });\n });\n }\n\n // Provide SQL keywords\n sqlKeywords.forEach(keyword => {\n suggestions.push({\n label: keyword,\n kind: monaco.languages.CompletionItemKind.Keyword,\n insertText: keyword + \" \",\n range,\n detail: \"SQL Keyword\",\n sortText: \"3\"\n });\n });\n\n // Heuristic: Suggest columns for tables that are mentioned in the current editor text\n const fullText = model.getValue();\n const activeTables = new Set<string>();\n for (const [, tables] of Object.entries(allSchemas)) {\n tables.forEach(table => {\n const regex = new RegExp(`\\\\b${table.tableName}\\\\b`, \"i\");\n if (regex.test(fullText)) {\n activeTables.add(table.tableName);\n }\n });\n }\n\n const addedColumns = new Set<string>();\n for (const [, tables] of Object.entries(allSchemas)) {\n tables.forEach(table => {\n if (activeTables.has(table.tableName)) {\n table.columns.forEach(col => {\n if (!addedColumns.has(col.name)) {\n addedColumns.add(col.name);\n suggestions.push({\n label: col.name,\n kind: monaco.languages.CompletionItemKind.Field,\n insertText: col.name,\n range,\n detail: `Column (${table.tableName})`,\n sortText: \"1\" // Prioritize columns from active tables\n });\n }\n });\n }\n });\n }\n }\n\n return { suggestions };\n\n }\n });\n\n if (autoFocus) {\n editor.focus();\n }\n };\n\n return (\n <div className={cls(\"relative w-full h-full overflow-hidden\", className)}>\n <Editor\n height=\"100%\"\n defaultLanguage=\"pgsql\"\n value={value}\n onChange={onChange}\n onMount={handleEditorOnMount}\n theme={mode === \"dark\" ? \"vs-dark\" : \"vs\"}\n options={{\n minimap: { enabled: false },\n fontSize: 14,\n lineNumbers: \"on\",\n scrollBeyondLastLine: false,\n automaticLayout: true,\n readOnly,\n tabSize: 2,\n wordWrap: \"on\"\n }}\n />\n </div>\n );\n};\n"],"mappings":"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"}
@@ -1,10 +1,11 @@
1
- import { t as MonacoEditor } from "./MonacoEditor-COZqrIJ1.js";
2
- import { ErrorView, useRebaseContext, useSnackbarController, useStudioCollectionRegistry, useTranslation } from "@rebasepro/core";
1
+ import { t as MonacoEditor } from "./MonacoEditor-D0_QljcX.js";
2
+ import { ErrorView, useRebaseContext, useSnackbarController, useStudioCollectionRegistry, useTranslation } from "@rebasepro/app";
3
3
  import { useCallback, useEffect, useMemo, useState } from "react";
4
4
  import { Alert, AlertTriangleIcon, Button, Chip, CircularProgress, DatabaseIcon, Dialog, DialogActions, DialogContent, DialogTitle, HelpCircleIcon, IconButton, KeyIcon, Link2Icon, LockIcon, MultiSelect, MultiSelectItem, Paper, RefreshCwIcon, ResizablePanels, Select, SelectItem, ShieldIcon, Tab, Tabs, TextField, Tooltip, Trash2Icon, Typography, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- import { isPostgresCollection } from "@rebasepro/types";
7
- import { JUNCTION_TABLES_SQL, REBASE_INTERNAL_PREFIXES, REBASE_INTERNAL_SCHEMAS } from "@rebasepro/common";
6
+ import { isPostgresCollectionConfig } from "@rebasepro/types";
7
+ import { getPolicyNamesForRule, getPolicyNamesForRules, getPolicyOperations } from "@rebasepro/utils";
8
+ import { JUNCTION_TABLES_SQL, REBASE_INTERNAL_PREFIXES, REBASE_INTERNAL_SCHEMAS, getJunctionSecurityRules, resolveJunctionSpecs } from "@rebasepro/common";
8
9
  //#region src/components/RLSEditor/PolicyEditor.tsx
9
10
  var COMMAND_OPTIONS = [
10
11
  "ALL",
@@ -138,9 +139,10 @@ var PolicyEditor = ({ policy, schema, table, onSave, onCancel }) => {
138
139
  });
139
140
  };
140
141
  return /* @__PURE__ */ jsxs(Fragment, { children: [
141
- /* @__PURE__ */ jsxs(DialogTitle, {
142
- className: "flex justify-between items-center w-full",
142
+ /* @__PURE__ */ jsxs(Typography, {
143
143
  variant: "h6",
144
+ gutterBottom: true,
145
+ className: "mt-8 mx-8 flex justify-between items-center w-full",
144
146
  children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: policy ? t("studio_policy_edit") : t("studio_policy_create") }), /* @__PURE__ */ jsxs("div", {
145
147
  className: "text-sm font-normal text-text-secondary dark:text-text-secondary-dark tracking-wide mt-1",
146
148
  children: [
@@ -837,32 +839,34 @@ var RLSEditor = ({ apiUrl = "" }) => {
837
839
  status: "live"
838
840
  };
839
841
  });
840
- if (activeCollection && isPostgresCollection(activeCollection) && activeCollection.securityRules) activeCollection.securityRules.forEach((rule) => {
841
- const ruleName = rule.name;
842
- if (!ruleName) return;
843
- if (policiesMap[ruleName]) policiesMap[ruleName] = {
844
- policyname: ruleName,
845
- tablename: activeTableData.tableName,
846
- permissive: (rule.mode || "permissive").toUpperCase(),
847
- cmd: (rule.operation || "ALL").toUpperCase(),
848
- roles: rule.roles || ["public"],
849
- qual: rule.using || null,
850
- with_check: rule.withCheck || null,
851
- status: "both"
852
- };
853
- else policiesMap[ruleName] = {
854
- policyname: ruleName,
855
- tablename: activeTableData.tableName,
856
- permissive: (rule.mode || "permissive").toUpperCase(),
857
- cmd: (rule.operation || "ALL").toUpperCase(),
858
- roles: rule.roles || ["public"],
859
- qual: rule.using || null,
860
- with_check: rule.withCheck || null,
861
- status: "code_only"
862
- };
842
+ if (activeCollection && isPostgresCollectionConfig(activeCollection) && activeCollection.securityRules) activeCollection.securityRules.forEach((rule) => {
843
+ const ops = getPolicyOperations(rule);
844
+ getPolicyNamesForRule(rule, activeTableData.tableName).forEach((policyName, opIdx) => {
845
+ policiesMap[policyName] = {
846
+ policyname: policyName,
847
+ tablename: activeTableData.tableName,
848
+ permissive: (rule.mode || "permissive").toUpperCase(),
849
+ cmd: (ops[opIdx] ?? rule.operation ?? "ALL").toUpperCase(),
850
+ roles: [...rule.roles ?? ["public"]],
851
+ qual: rule.using || null,
852
+ with_check: rule.withCheck || null,
853
+ status: policiesMap[policyName] ? "both" : "code_only"
854
+ };
855
+ });
863
856
  });
857
+ if (!activeCollection) try {
858
+ const spec = resolveJunctionSpecs(collectionRegistry.collections ?? []).get(activeTableData.tableName);
859
+ if (spec) {
860
+ const generatedNames = getPolicyNamesForRules(getJunctionSecurityRules(spec), spec.table);
861
+ for (const p of Object.values(policiesMap)) if (generatedNames.has(p.policyname)) p.status = "both";
862
+ }
863
+ } catch {}
864
864
  return Object.values(policiesMap).sort((a, b) => a.policyname.localeCompare(b.policyname));
865
- }, [activeTableData, activeCollection]);
865
+ }, [
866
+ activeTableData,
867
+ activeCollection,
868
+ collectionRegistry.collections
869
+ ]);
866
870
  const rlsStats = useMemo(() => {
867
871
  return {
868
872
  total: tables.length,
@@ -1239,7 +1243,7 @@ var RLSEditor = ({ apiUrl = "" }) => {
1239
1243
  withCheck: newPolicy.with_check || void 0,
1240
1244
  roles: newPolicy.roles
1241
1245
  };
1242
- const existingRules = (isPostgresCollection(activeCollection) ? activeCollection.securityRules : void 0) || [];
1246
+ const existingRules = (isPostgresCollectionConfig(activeCollection) ? activeCollection.securityRules : void 0) || [];
1243
1247
  let newRules;
1244
1248
  if (editingPolicy === "new") newRules = [...existingRules, rule];
1245
1249
  else newRules = existingRules.map((r) => r.name === editingPolicy.policyname ? rule : r);
@@ -1331,7 +1335,7 @@ var RLSEditor = ({ apiUrl = "" }) => {
1331
1335
  }), /* @__PURE__ */ jsx(Typography, {
1332
1336
  variant: "caption",
1333
1337
  className: "opacity-80",
1334
- children: "This is an auto-generated junction table for a many-to-many relation. Its access is typically managed through the related collections' policies. You can still add RLS policies directly if needed."
1338
+ children: "This is an auto-generated junction table for a many-to-many relation. Rebase derives its policies: rows are readable when both related rows are, and writable following the declaring collection's update rules (plus the server/admin baseline). You can still add RLS policies directly to broaden access."
1335
1339
  })] })]
1336
1340
  })
1337
1341
  }),
@@ -1436,7 +1440,7 @@ var RLSEditor = ({ apiUrl = "" }) => {
1436
1440
  withCheck: policy.with_check || void 0,
1437
1441
  roles: policy.roles
1438
1442
  };
1439
- const newRules = [...(isPostgresCollection(activeCollection) ? activeCollection.securityRules : void 0) || [], rule];
1443
+ const newRules = [...(isPostgresCollectionConfig(activeCollection) ? activeCollection.securityRules : void 0) || [], rule];
1440
1444
  try {
1441
1445
  if (!(await fetch(`${apiUrl}/api/schema-editor/collection/save`, {
1442
1446
  method: "POST",
@@ -1553,4 +1557,4 @@ var RLSEditor = ({ apiUrl = "" }) => {
1553
1557
  //#endregion
1554
1558
  export { RLSEditor };
1555
1559
 
1556
- //# sourceMappingURL=RLSEditor-BM64laoW.js.map
1560
+ //# sourceMappingURL=RLSEditor-D6adwB6e.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RLSEditor-D6adwB6e.js","names":[],"sources":["../src/components/RLSEditor/PolicyEditor.tsx","../src/components/RLSEditor/RLSEditor.tsx"],"sourcesContent":["\nimport React, { useState, useEffect } from \"react\";\nimport {\n Button,\n cls,\n defaultBorderMixin,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n HelpCircleIcon,\n IconButton,\n iconSize,\n MultiSelect,\n MultiSelectItem,\n Paper,\n Select,\n SelectItem,\n TextField,\n Typography\n} from \"@rebasepro/ui\";\nimport { useTranslation } from \"@rebasepro/app\";\nimport { MonacoEditor } from \"../SQLEditor/MonacoEditor\";\nimport { PostgresPolicy } from \"./RLSEditor\";\n\nexport interface PolicyEditorProps {\n policy?: PostgresPolicy;\n schema: string;\n table: string;\n onSave: (policyData: Partial<PostgresPolicy>) => void;\n onCancel: () => void;\n}\n\ntype PolicyCommand = \"ALL\" | \"SELECT\" | \"INSERT\" | \"UPDATE\" | \"DELETE\";\nconst COMMAND_OPTIONS: PolicyCommand[] = [\"ALL\", \"SELECT\", \"INSERT\", \"UPDATE\", \"DELETE\"];\nconst ROLE_OPTIONS = [\"public\", \"authenticated\", \"anon\", \"admin\"];\n\ninterface PolicyPreset {\n id: string;\n label: string;\n description: string;\n policyname: string;\n cmd: PolicyCommand;\n permissive: \"PERMISSIVE\" | \"RESTRICTIVE\";\n roles: string[];\n qual: string;\n with_check: string;\n}\n\nconst POLICY_PRESETS: PolicyPreset[] = [\n {\n id: \"public_read\",\n label: \"Enable read access to everyone\",\n description: \"Anyone can read data, regardless of authentication status.\",\n policyname: \"Enable read access for all users\",\n cmd: \"SELECT\",\n permissive: \"PERMISSIVE\",\n roles: [\"public\"],\n qual: \"true\",\n with_check: \"\"\n },\n {\n id: \"auth_read\",\n label: \"Enable read access for authenticated users only\",\n description: \"Only logged-in users are allowed to read data.\",\n policyname: \"Enable read access for authenticated users\",\n cmd: \"SELECT\",\n permissive: \"PERMISSIVE\",\n roles: [\"authenticated\"],\n qual: \"true\",\n with_check: \"\"\n },\n {\n id: \"auth_insert\",\n label: \"Enable insert for authenticated users only\",\n description: \"Only logged-in users are allowed to insert new data.\",\n policyname: \"Enable insert for authenticated users only\",\n cmd: \"INSERT\",\n permissive: \"PERMISSIVE\",\n roles: [\"authenticated\"],\n qual: \"\",\n with_check: \"true\"\n },\n {\n id: \"user_select_own\",\n label: \"Users can read their own rows\",\n description: \"Users can only read rows where the user_id matches their auth.uid()\",\n policyname: \"Users can select their own data\",\n cmd: \"SELECT\",\n permissive: \"PERMISSIVE\",\n roles: [\"authenticated\"],\n qual: \"auth.uid() = user_id\",\n with_check: \"\"\n },\n {\n id: \"user_update_own\",\n label: \"Users can update their own rows\",\n description: \"Users can only update rows where the user_id matches their auth.uid()\",\n policyname: \"Users can update their own data\",\n cmd: \"UPDATE\",\n permissive: \"PERMISSIVE\",\n roles: [\"authenticated\"],\n qual: \"auth.uid() = user_id\",\n with_check: \"auth.uid() = user_id\"\n },\n {\n id: \"user_delete_own\",\n label: \"Users can delete their own rows\",\n description: \"Users can only delete rows where the user_id matches their auth.uid()\",\n policyname: \"Users can delete their own data\",\n cmd: \"DELETE\",\n permissive: \"PERMISSIVE\",\n roles: [\"authenticated\"],\n qual: \"auth.uid() = user_id\",\n with_check: \"\"\n }\n];\n\nexport const PolicyEditor = ({\n policy,\n schema,\n table,\n onSave,\n onCancel\n}: PolicyEditorProps) => {\n\n const { t } = useTranslation();\n const [name, setName] = useState(\"\");\n const [helpOpen, setHelpOpen] = useState(false);\n const [behavior, setBehavior] = useState<\"PERMISSIVE\" | \"RESTRICTIVE\">(\"PERMISSIVE\");\n const [command, setCommand] = useState<PolicyCommand>(\"ALL\");\n const [roles, setRoles] = useState<string[]>([\"public\"]);\n const [usingExpr, setUsingExpr] = useState<string>(\"\");\n const [checkExpr, setCheckExpr] = useState<string>(\"\");\n\n const [selectedPreset, setSelectedPreset] = useState<string>(\"\");\n\n useEffect(() => {\n if (policy) {\n setName(policy.policyname || \"\");\n setBehavior(policy.permissive || \"PERMISSIVE\");\n setCommand((policy.cmd as PolicyCommand) || \"ALL\");\n\n const initialRoles = policy.roles\n ? (Array.isArray(policy.roles) ? policy.roles : [policy.roles])\n : [\"public\"];\n setRoles(initialRoles as string[]);\n\n setUsingExpr(policy.qual || \"\");\n setCheckExpr(policy.with_check || \"\");\n } else {\n setName(\"\");\n setBehavior(\"PERMISSIVE\");\n setCommand(\"ALL\");\n setRoles([\"public\"]);\n setUsingExpr(\"\");\n setCheckExpr(\"\");\n setSelectedPreset(\"\");\n }\n }, [policy]);\n\n const handlePresetChange = (presetId: string) => {\n const preset = POLICY_PRESETS.find(p => p.id === presetId);\n if (!preset) return;\n\n setSelectedPreset(presetId);\n setName(preset.policyname);\n setBehavior(preset.permissive);\n setCommand(preset.cmd);\n setRoles(preset.roles);\n setUsingExpr(preset.qual);\n setCheckExpr(preset.with_check);\n };\n\n const showCheck = command === \"ALL\" || command === \"INSERT\" || command === \"UPDATE\";\n\n const handleSave = () => {\n onSave({\n policyname: name,\n permissive: behavior,\n cmd: command,\n roles: roles,\n qual: usingExpr,\n with_check: showCheck ? checkExpr : null\n });\n };\n\n return (\n <>\n {/* Inline header: this editor renders as a full pane, not inside a Dialog,\n so DialogTitle (Radix-bound) cannot be used here. */}\n <Typography variant=\"h6\" gutterBottom className=\"mt-8 mx-8 flex justify-between items-center w-full\">\n <div>\n <div>{policy ? t(\"studio_policy_edit\") : t(\"studio_policy_create\")}</div>\n <div className=\"text-sm font-normal text-text-secondary dark:text-text-secondary-dark tracking-wide mt-1\">\n {t(\"studio_policy_defining_rules\")} <span className=\"font-mono text-primary bg-primary-bg dark:bg-primary-bg-dark px-1 py-0.5 rounded\">{schema}.{table}</span>\n </div>\n </div>\n <IconButton size=\"small\" onClick={() => setHelpOpen(true)}>\n <HelpCircleIcon size={iconSize.smallest}/>\n </IconButton>\n </Typography>\n\n <DialogContent className=\"p-4 md:p-6 border-t dark:border-surface-950 bg-surface-50 dark:bg-surface-950\" includeMargin={false}>\n <div className=\"max-w-4xl mx-auto\">\n <Paper className={cls(\"p-4 md:p-6 flex flex-col gap-6 bg-white dark:bg-surface-900 border-none sm:border-solid rounded-none sm:rounded-xl\", defaultBorderMixin)}>\n\n {/* Presets - only for new policies */}\n {!policy && (\n <div className=\"flex flex-col gap-1.5 bg-primary/5 dark:bg-primary-bg-dark/20 p-3 sm:p-4 rounded-lg border border-primary/10 dark:border-primary/20\">\n <Typography variant=\"caption\" className=\"text-primary dark:text-primary-light uppercase tracking-wider\">{t(\"studio_policy_template\")}</Typography>\n <Select\n size=\"small\"\n value={selectedPreset}\n onValueChange={handlePresetChange}\n position=\"item-aligned\"\n placeholder={t(\"studio_policy_select_template\")}\n className=\"bg-white dark:bg-surface-950\"\n >\n {POLICY_PRESETS.map((preset) => (\n <SelectItem key={preset.id} value={preset.id}>\n <div className=\"flex flex-col text-left\">\n <span className=\"text-sm\">{preset.label}</span>\n <span className=\"text-xs text-text-secondary dark:text-text-secondary-dark\">{preset.description}</span>\n </div>\n </SelectItem>\n ))}\n </Select>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6\">\n {/* Policy Name */}\n <div className=\"flex flex-col gap-1.5\">\n <Typography variant=\"caption\" className=\"uppercase tracking-wider text-text-secondary\">{t(\"studio_policy_name\")}</Typography>\n <TextField\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t(\"studio_policy_name_placeholder\")}\n className=\"w-full\"\n />\n </div>\n\n {/* Behavior */}\n <div className=\"flex flex-col gap-1.5\">\n <Typography variant=\"caption\" className=\"uppercase tracking-wider text-text-secondary\">\n {t(\"studio_policy_behavior\")} <code className=\"text-[10px] bg-surface-200 dark:bg-surface-950 text-text-secondary dark:text-text-secondary-dark px-1 py-0.5 rounded ml-1\">AS</code>\n </Typography>\n <Select\n value={behavior}\n onValueChange={(val) => setBehavior(val as \"PERMISSIVE\" | \"RESTRICTIVE\")}\n position=\"item-aligned\"\n >\n <SelectItem value=\"PERMISSIVE\">\n <div className=\"flex flex-col text-left\">\n <span className=\"\">{t(\"studio_policy_permissive\")}</span>\n <span className=\"text-xs text-text-secondary dark:text-text-secondary-dark\">{t(\"studio_policy_permissive_desc\")}</span>\n </div>\n </SelectItem>\n <SelectItem value=\"RESTRICTIVE\">\n <div className=\"flex flex-col text-left\">\n <span className=\"\">{t(\"studio_policy_restrictive\")}</span>\n <span className=\"text-xs text-text-secondary dark:text-text-secondary-dark\">{t(\"studio_policy_restrictive_desc\")}</span>\n </div>\n </SelectItem>\n </Select>\n </div>\n </div>\n\n {/* Command */}\n <div className=\"flex flex-col gap-1.5\">\n <Typography variant=\"caption\" className=\"uppercase tracking-wider text-text-secondary\">\n {t(\"studio_policy_command\")} <code className=\"text-[10px] bg-surface-200 dark:bg-surface-950 text-text-secondary dark:text-text-secondary-dark px-1 py-0.5 rounded ml-1\">FOR</code>\n </Typography>\n <div className=\"flex flex-wrap gap-1.5\">\n {COMMAND_OPTIONS.map(cmd => (\n <Button\n key={cmd}\n size=\"small\"\n variant={command === cmd ? \"filled\" : \"text\"}\n color=\"neutral\"\n onClick={() => setCommand(cmd)}\n className=\"min-w-[80px]\"\n >\n {cmd}\n </Button>\n ))}\n </div>\n </div>\n\n {/* Roles */}\n <div className=\"flex flex-col gap-1.5\">\n <Typography variant=\"caption\" className=\"uppercase tracking-wider text-text-secondary\">\n {t(\"studio_policy_target_roles\")} <code className=\"text-[10px] bg-surface-200 dark:bg-surface-950 text-text-secondary dark:text-text-secondary-dark px-1 py-0.5 rounded ml-1\">TO</code>\n </Typography>\n <MultiSelect\n size=\"small\"\n value={roles}\n onValueChange={setRoles}\n placeholder={t(\"studio_policy_roles_placeholder\")}\n >\n {ROLE_OPTIONS.map(role => (\n <MultiSelectItem key={role} value={role}>\n {role}\n </MultiSelectItem>\n ))}\n </MultiSelect>\n </div>\n\n </Paper>\n\n <div className=\"mt-8 flex flex-col gap-4\">\n {/* USING Expression */}\n {command !== \"INSERT\" && (\n <div className=\"flex flex-col gap-1.5\">\n <div className=\"flex flex-col gap-0.5\">\n <Typography variant=\"caption\" className=\"uppercase tracking-wider text-text-secondary\">{t(\"studio_policy_using_expr\")}</Typography>\n <Typography variant=\"caption\" className=\"text-text-secondary opacity-70\">{t(\"studio_policy_using_expr_desc\")}</Typography>\n </div>\n <div className={cls(\"h-32 border rounded-md overflow-hidden bg-white dark:bg-[#1e1e1e]\", defaultBorderMixin)}>\n <MonacoEditor\n value={usingExpr}\n onChange={(v) => setUsingExpr(v || \"\")}\n readOnly={false}\n autoFocus={true}\n />\n </div>\n </div>\n )}\n\n {/* WITH CHECK Expression */}\n {showCheck && (\n <div className=\"flex flex-col gap-1.5 mt-2\">\n <div className=\"flex flex-col gap-0.5\">\n <Typography variant=\"caption\" className=\"uppercase tracking-wider text-text-secondary\">{t(\"studio_policy_check_expr\")}</Typography>\n <Typography variant=\"caption\" className=\"text-text-secondary opacity-70\">{t(\"studio_policy_check_expr_desc\")}</Typography>\n </div>\n <div className={cls(\"h-32 border rounded-md overflow-hidden bg-white dark:bg-[#1e1e1e]\", defaultBorderMixin)}>\n <MonacoEditor\n value={checkExpr}\n onChange={(v) => setCheckExpr(v || \"\")}\n readOnly={false}\n autoFocus={command === \"INSERT\"}\n />\n </div>\n </div>\n )}\n </div>\n\n </div>\n </DialogContent>\n\n <DialogActions>\n <Button size=\"small\" variant=\"text\" color=\"neutral\" onClick={onCancel}>\n {t(\"studio_policy_cancel\")}\n </Button>\n <Button size=\"small\" variant=\"filled\" color=\"primary\" onClick={handleSave} disabled={!name}>\n {t(\"studio_policy_save\")}\n </Button>\n </DialogActions>\n\n <Dialog open={helpOpen} onOpenChange={setHelpOpen} maxWidth=\"3xl\">\n <DialogTitle hidden>Row-Level Security Help</DialogTitle>\n <DialogContent className=\"p-4 sm:p-6 lg:p-8 flex flex-col gap-6\">\n <div>\n <Typography variant=\"h5\" className=\"mb-2\">{t(\"studio_policy_help_title\")}</Typography>\n <Typography className=\"text-text-secondary dark:text-text-secondary-dark\">\n {t(\"studio_policy_help_intro\")}\n </Typography>\n </div>\n\n <div className=\"flex flex-col gap-4\">\n <Paper className={cls(\"p-4 sm:p-5 flex flex-col gap-1\", defaultBorderMixin)}>\n <Typography variant=\"subtitle2\" className=\"text-primary dark:text-primary-light font-medium\">{t(\"studio_policy_help_step1_title\")}</Typography>\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {t(\"studio_policy_help_step1_desc\")}\n </Typography>\n </Paper>\n\n <Paper className={cls(\"p-4 sm:p-5 flex flex-col gap-1\", defaultBorderMixin)}>\n <Typography variant=\"subtitle2\" className=\"text-primary dark:text-primary-light font-medium\">{t(\"studio_policy_help_step2_title\")}</Typography>\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark mb-1\">\n {t(\"studio_policy_help_step2_desc\")}\n </Typography>\n <ul className=\"list-disc pl-5 space-y-1 text-sm text-text-secondary dark:text-text-secondary-dark\">\n <li><strong>public</strong>: {t(\"studio_policy_help_role_public\")}</li>\n <li><strong>authenticated</strong>: {t(\"studio_policy_help_role_authenticated\")}</li>\n <li><strong>anon</strong>: {t(\"studio_policy_help_role_anon\")}</li>\n </ul>\n </Paper>\n\n <Paper className={cls(\"p-4 sm:p-5 flex flex-col gap-1\", defaultBorderMixin)}>\n <Typography variant=\"subtitle2\" className=\"text-primary dark:text-primary-light font-medium\">{t(\"studio_policy_help_step3_title\")}</Typography>\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark mb-1\">\n {t(\"studio_policy_help_step3_desc\")}\n </Typography>\n <div className={cls(\"bg-surface-100 dark:bg-surface-950 px-3 py-2 rounded-md font-mono text-sm my-2\", defaultBorderMixin)}>\n Example: auth.uid() = user_id\n </div>\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {t(\"studio_policy_help_step3_example\")}\n </Typography>\n </Paper>\n\n <Paper className={cls(\"p-4 sm:p-5 flex flex-col gap-1\", defaultBorderMixin)}>\n <Typography variant=\"subtitle2\" className=\"text-primary dark:text-primary-light font-medium\">{t(\"studio_policy_help_step4_title\")}</Typography>\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark mb-1\">\n {t(\"studio_policy_help_step4_desc\")}\n </Typography>\n <div className={cls(\"bg-surface-100 dark:bg-surface-950 px-3 py-2 rounded-md font-mono text-sm my-2\", defaultBorderMixin)}>\n Example: auth.uid() = user_id\n </div>\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {t(\"studio_policy_help_step4_example\")}\n </Typography>\n </Paper>\n\n <Paper className={cls(\"p-4 sm:p-5 flex flex-col gap-2 bg-primary/5 dark:bg-primary-bg-dark/10\", defaultBorderMixin)}>\n <Typography variant=\"subtitle2\" className=\"text-primary dark:text-primary-light font-medium\">{t(\"studio_policy_help_auth_vars_title\")}</Typography>\n <Typography variant=\"body2\" className=\"text-text-secondary dark:text-text-secondary-dark\">\n {t(\"studio_policy_help_auth_vars_desc\")}\n </Typography>\n <ul className=\"list-disc pl-5 space-y-2 text-sm text-text-secondary dark:text-text-secondary-dark font-normal\">\n <li>\n <code className=\"bg-surface-100 dark:bg-surface-950 px-1.5 py-0.5 rounded mr-1 whitespace-nowrap\">auth.uid()</code>\n <span className=\"block mt-0.5\">Returns the current user&apos;s ID as text. Example: <code className=\"bg-surface-100 dark:bg-surface-950 px-1 py-0.5 rounded text-[11px]\">auth.uid() = user_id</code></span>\n </li>\n <li>\n <code className=\"bg-surface-100 dark:bg-surface-950 px-1.5 py-0.5 rounded mr-1 whitespace-nowrap\">auth.jwt()</code>\n <span className=\"block mt-0.5\">Returns the full JWT payload as JSONB so you can check custom claims. Example: <code className=\"bg-surface-100 dark:bg-surface-950 px-1 py-0.5 rounded text-[11px]\">auth.jwt() -&gt;&gt; &apos;email&apos; = &apos;admin@example.com&apos;</code></span>\n </li>\n <li>\n <code className=\"bg-surface-100 dark:bg-surface-950 px-1.5 py-0.5 rounded mr-1 whitespace-nowrap\">auth.roles()</code>\n <span className=\"block mt-0.5\">Returns the user&apos;s role IDs as a comma-separated string. Best used with: <code className=\"bg-surface-100 dark:bg-surface-950 px-1 py-0.5 rounded text-[11px]\">string_to_array(auth.roles(), &apos;,&apos;) @&gt; ARRAY[&apos;admin&apos;]</code></span>\n </li>\n </ul>\n </Paper>\n </div>\n\n <div className={cls(\"mt-2 flex flex-col sm:flex-row justify-between items-start sm:items-center bg-primary/5 dark:bg-primary-bg-dark/10 p-4 rounded-xl border border-primary/10 dark:border-primary/20\", defaultBorderMixin)}>\n <Typography variant=\"body2\" className=\"text-primary dark:text-primary-light mb-4 sm:mb-0 max-w-md\">\n {t(\"studio_policy_help_docs_cta\")}\n </Typography>\n <Button\n component=\"a\"\n href=\"https://www.postgresql.org/docs/current/sql-createpolicy.html\"\n target=\"_blank\"\n variant=\"outlined\"\n color=\"primary\"\n size=\"small\"\n className=\"whitespace-nowrap flex-shrink-0\"\n >\n {t(\"studio_policy_help_read_docs\")}\n </Button>\n </div>\n </DialogContent>\n <DialogActions className=\"p-4 sm:px-6 sm:pb-6 pt-0 border-t-0\">\n <Button onClick={() => setHelpOpen(false)} variant=\"filled\" color=\"primary\">{t(\"studio_policy_help_got_it\")}</Button>\n </DialogActions>\n </Dialog>\n </>\n );\n};\n","\nimport { useStudioCollectionRegistry } from \"@rebasepro/app\";\nimport React, { useState, useEffect, useCallback, useMemo } from \"react\";\nimport {\n Alert,\n AlertTriangleIcon,\n Button,\n Chip,\n CircularProgress,\n cls,\n DatabaseIcon,\n defaultBorderMixin,\n IconButton,\n iconSize,\n KeyIcon,\n Link2Icon,\n LockIcon,\n Paper,\n RefreshCwIcon,\n ResizablePanels,\n ShieldIcon,\n Tab,\n Tabs,\n Tooltip,\n Trash2Icon,\n Typography\n} from \"@rebasepro/ui\";\nimport { useRebaseContext, useSnackbarController, ErrorView, useTranslation } from \"@rebasepro/app\";\nimport { isPostgresCollectionConfig } from \"@rebasepro/types\";\nimport { REBASE_INTERNAL_SCHEMAS, REBASE_INTERNAL_PREFIXES, JUNCTION_TABLES_SQL } from \"@rebasepro/common\";\nimport { getPolicyNamesForRule, getPolicyNamesForRules, getPolicyOperations } from \"@rebasepro/utils\";\nimport { resolveJunctionSpecs, getJunctionSecurityRules } from \"@rebasepro/common\";\nimport { PolicyEditor } from \"./PolicyEditor\";\n\ntype TableCategory = \"collection\" | \"junction\" | \"internal\" | \"other\";\n\nfunction classifyTableClient(\n tableName: string,\n schemaName: string,\n junctionTableNames: Set<string>,\n isMappedToCollection: boolean\n): TableCategory {\n if (\n REBASE_INTERNAL_SCHEMAS.includes(schemaName) ||\n REBASE_INTERNAL_PREFIXES.some((prefix) => tableName.startsWith(prefix))\n ) {\n return \"internal\";\n }\n if (isMappedToCollection) return \"collection\";\n if (junctionTableNames.has(tableName)) return \"junction\";\n return \"other\";\n}\n\n/**\n * Validates and double-quotes a SQL identifier to prevent injection.\n * Only allows safe Postgres identifiers (letters, digits, underscores).\n * Throws if the identifier contains unsafe characters.\n */\nfunction sanitizeSqlIdentifier(name: string): string {\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new Error(`Invalid SQL identifier: \"${name}\". Only letters, digits, and underscores are allowed.`);\n }\n return `\"${name}\"`;\n}\n\nexport interface PostgresPolicy {\n policyname: string;\n tablename: string;\n permissive: \"PERMISSIVE\" | \"RESTRICTIVE\";\n roles: string[];\n cmd: \"SELECT\" | \"INSERT\" | \"UPDATE\" | \"DELETE\" | \"ALL\";\n qual: string | null; // USING clause\n with_check: string | null; // WITH CHECK clause\n status?: \"live\" | \"code_only\" | \"both\";\n}\n\ninterface TableRLSStatus {\n schemaName: string;\n tableName: string;\n rlsEnabled: boolean;\n policies: PostgresPolicy[];\n}\n\n// ─── Sidebar helper components ──────────────────────────────────────\n\nfunction SidebarSection({ title, icon, expanded, onToggle, count, children }: {\n title: string;\n icon: React.ReactNode;\n expanded: boolean;\n onToggle: () => void;\n count?: number;\n children: React.ReactNode;\n}) {\n return (\n <div className=\"mb-2\">\n <div\n className=\"flex items-center p-1.5 cursor-pointer hover:bg-surface-100 dark:hover:bg-surface-900 rounded transition-colors\"\n onClick={onToggle}\n >\n <svg className={cls(\"w-3 h-3 mr-1.5 transition-transform text-text-disabled dark:text-text-disabled-dark\", expanded ? \"rotate-90\" : \"\")} fill=\"currentColor\" viewBox=\"0 0 20 20\"><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\"/></svg>\n {icon}\n <Typography variant=\"body2\" className=\"text-text-primary dark:text-text-primary-dark font-medium text-xs truncate flex-grow ml-1.5\">{title}</Typography>\n {count !== undefined && (\n <span className=\"text-[10px] text-text-disabled dark:text-text-disabled-dark font-medium tabular-nums mr-1\">{count}</span>\n )}\n </div>\n {expanded && (\n <div className=\"ml-3 mt-0.5 space-y-0.5\">\n {children}\n </div>\n )}\n </div>\n );\n}\n\nfunction SidebarTableRow({ table, isSelected, onSelect, badge, dimmed, t }: {\n table: TableRLSStatus;\n isSelected: boolean;\n onSelect: () => void;\n badge?: string;\n dimmed?: boolean;\n t: (key: string) => string;\n}) {\n return (\n <div\n onClick={onSelect}\n className={cls(\n \"flex items-center p-1 cursor-pointer rounded transition-colors group relative\",\n isSelected\n ? \"bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-light\"\n : \"hover:bg-surface-100 dark:hover:bg-surface-900 text-text-secondary dark:text-text-secondary-dark\",\n dimmed && !isSelected && \"opacity-60\"\n )}\n >\n <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\"><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\"/></svg>\n <Typography variant=\"body2\" className=\"text-xs truncate flex-1 min-w-0\">{table.tableName}</Typography>\n <div className=\"flex items-center gap-1.5 shrink-0 ml-2\">\n {badge && (\n <span className=\"text-[9px] uppercase tracking-wider font-semibold text-text-disabled dark:text-text-disabled-dark bg-surface-200 dark:bg-surface-800 rounded px-1 py-px\">\n {badge}\n </span>\n )}\n {table.rlsEnabled ? (\n <Tooltip title={t(\"studio_rls_enabled\")}>\n <div className=\"w-1.5 h-1.5 rounded-full bg-green-500\"/>\n </Tooltip>\n ) : (\n <Tooltip title={t(\"studio_rls_disabled\")}>\n <div className=\"w-1.5 h-1.5 rounded-full bg-orange-400 opacity-50\"/>\n </Tooltip>\n )}\n <span className=\"text-[10px] opacity-40 group-hover:opacity-100 min-w-[1.2rem] text-right font-medium\">\n {table.policies.length}\n </span>\n </div>\n </div>\n );\n}\n\nexport const RLSEditor = ({ apiUrl = \"\" }: { apiUrl?: string }) => {\n const { databaseAdmin } = useRebaseContext();\n const snackbarController = useSnackbarController();\n const collectionRegistry = useStudioCollectionRegistry();\n const { t } = useTranslation();\n\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [tables, setTables] = useState<TableRLSStatus[]>([]);\n const [selectedTable, setSelectedTable] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState(0);\n const [junctionTableNames, setJunctionTableNames] = useState<Set<string>>(new Set());\n\n const [editingPolicy, setEditingPolicy] = useState<PostgresPolicy | \"new\" | null>(null);\n\n const [sidebarSize, setSidebarSize] = useState(() => {\n try {\n const saved = localStorage.getItem(\"rebase_rls_editor_sidebar_size\");\n return saved !== null ? parseFloat(saved) : 20;\n } catch (e) {\n return 20;\n }\n });\n\n const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({\n collection: true,\n other: true,\n internal: false\n });\n\n // Sidebar tab: \"tables\" or \"info\"\n const [sidebarTab, setSidebarTab] = useState<\"tables\" | \"info\">(\"tables\");\n\n useEffect(() => {\n try {\n localStorage.setItem(\"rebase_rls_editor_sidebar_size\", sidebarSize.toString());\n } catch (e) { /* ignore */ }\n }, [sidebarSize]);\n\n const fetchRLSData = useCallback(async () => {\n if (!databaseAdmin?.executeSql) {\n setError(t(\"studio_sql_sql_not_supported\"));\n setIsLoading(false);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n try {\n // 1. Fetch tables and whether RLS is enabled\n const tablesSql = `\n SELECT \n schemaname, \n tablename, \n rowsecurity \n FROM pg_tables \n WHERE schemaname NOT IN ('information_schema', 'pg_catalog')\n ORDER BY schemaname, tablename;\n `;\n const tablesResult = await databaseAdmin!.executeSql!(tablesSql);\n\n // 2. Fetch all policies\n const policiesSql = `\n SELECT \n schemaname,\n tablename,\n policyname,\n permissive,\n roles,\n cmd,\n qual,\n with_check\n FROM pg_policies\n WHERE schemaname NOT IN ('information_schema', 'pg_catalog');\n `;\n const policiesResult = await databaseAdmin!.executeSql!(policiesSql);\n\n const extractRows = (result: unknown): Record<string, unknown>[] => {\n if (result && typeof result === \"object\" && \"rows\" in result && Array.isArray((result as { rows: Record<string, unknown>[] }).rows)) {\n return (result as { rows: Record<string, unknown>[] }).rows;\n }\n if (Array.isArray(result)) return result as Record<string, unknown>[];\n return [];\n };\n\n const tRows = extractRows(tablesResult);\n const pRows = extractRows(policiesResult);\n\n const tableMap: Record<string, TableRLSStatus> = {};\n\n tRows.forEach((tRow: Record<string, unknown>) => {\n const t = tRow as { schemaname?: string, SCHEMANAME?: string, tablename?: string, TABLENAME?: string, rowsecurity?: boolean, ROWSECURITY?: boolean };\n const schema = t.schemaname || t.SCHEMANAME || \"public\";\n const table = t.tablename || t.TABLENAME || \"\";\n const rlsEnabled = t.rowsecurity || t.ROWSECURITY || false;\n\n const key = `${schema}.${table}`;\n tableMap[key] = {\n schemaName: schema,\n tableName: table,\n rlsEnabled: rlsEnabled,\n policies: []\n };\n });\n\n pRows.forEach((pRow: Record<string, unknown>) => {\n const p = pRow as { schemaname?: string, SCHEMANAME?: string, tablename?: string, TABLENAME?: string, roles?: string | string[], ROLES?: string | string[], policyname?: string, POLICYNAME?: string, permissive?: \"PERMISSIVE\" | \"RESTRICTIVE\", PERMISSIVE?: \"PERMISSIVE\" | \"RESTRICTIVE\", cmd?: \"SELECT\" | \"INSERT\" | \"UPDATE\" | \"DELETE\" | \"ALL\", CMD?: \"SELECT\" | \"INSERT\" | \"UPDATE\" | \"DELETE\" | \"ALL\", qual?: string | null, QUAL?: string | null, with_check?: string | null, WITH_CHECK?: string | null };\n const schema = p.schemaname || p.SCHEMANAME || \"public\";\n const table = p.tablename || p.TABLENAME || \"\";\n const key = `${schema}.${table}`;\n\n if (tableMap[key]) {\n // Postgres roles come back as an array string like \"{public}\" or literal array\n let parsedRoles: string[] = [];\n const r = p.roles || p.ROLES;\n if (Array.isArray(r)) {\n parsedRoles = r;\n } else if (typeof r === \"string\") {\n parsedRoles = r.replace(/^{|}$/g, \"\").split(\",\").map(s => s.trim());\n }\n\n tableMap[key].policies.push({\n policyname: p.policyname || p.POLICYNAME || \"\",\n tablename: table,\n permissive: p.permissive || p.PERMISSIVE || \"PERMISSIVE\",\n roles: parsedRoles,\n cmd: p.cmd || p.CMD || \"ALL\",\n qual: p.qual || p.QUAL || null,\n with_check: p.with_check || p.WITH_CHECK || null\n });\n }\n });\n\n const sortedTables = Object.values(tableMap).sort((a, b) => a.tableName.localeCompare(b.tableName));\n setTables(sortedTables);\n\n // Detect junction tables (where all columns are FKs)\n try {\n const junctionResult = await databaseAdmin!.executeSql!(JUNCTION_TABLES_SQL);\n const jRows = extractRows(junctionResult);\n setJunctionTableNames(new Set(\n jRows.map((r: Record<string, unknown>) => r.table_name as string).filter(Boolean)\n ));\n } catch {\n // Junction detection is best-effort\n }\n\n if (sortedTables.length > 0 && !selectedTable) {\n // Auto-select first public/collection table, skip internal\n const firstUserTable = sortedTables.find(t => !REBASE_INTERNAL_SCHEMAS.includes(t.schemaName));\n if (firstUserTable) {\n setSelectedTable(`${firstUserTable.schemaName}.${firstUserTable.tableName}`);\n } else {\n setSelectedTable(`${sortedTables[0].schemaName}.${sortedTables[0].tableName}`);\n }\n }\n\n } catch (e: unknown) {\n console.error(\"RLS fetch error:\", e);\n setError(\"Failed to fetch RLS policies: \" + (e instanceof Error ? e.message : String(e)));\n } finally {\n setIsLoading(false);\n }\n }, [databaseAdmin, selectedTable]);\n\n useEffect(() => {\n setEditingPolicy(null);\n }, [selectedTable]);\n\n useEffect(() => {\n fetchRLSData();\n }, [fetchRLSData]);\n\n const activeTableData = useMemo(() => {\n if (!selectedTable) return null;\n return tables.find(t => `${t.schemaName}.${t.tableName}` === selectedTable) || null;\n }, [selectedTable, tables]);\n\n /** Categorize tables into 4 buckets for the sidebar. */\n const categorizedTables = useMemo(() => {\n const groups: Record<TableCategory, TableRLSStatus[]> = {\n collection: [],\n junction: [],\n internal: [],\n other: []\n };\n\n tables.forEach(table => {\n const isMapped = !!collectionRegistry.collections?.find(\n (c: { id?: string, path?: string, table?: string, slug?: string, collectionId?: string }) =>\n c.id === table.tableName ||\n c.path === table.tableName ||\n c.table === table.tableName ||\n c.slug === table.tableName ||\n c.collectionId === table.tableName\n );\n const cat = classifyTableClient(table.tableName, table.schemaName, junctionTableNames, isMapped);\n groups[cat].push(table);\n });\n\n return groups;\n }, [tables, junctionTableNames, collectionRegistry.collections]);\n\n const activeCollection = useMemo(() => {\n if (!activeTableData) return null;\n return collectionRegistry.collections?.find((c: { id?: string, path?: string, table?: string, slug?: string, collectionId?: string }) =>\n c.id === activeTableData.tableName ||\n c.path === activeTableData.tableName ||\n c.table === activeTableData.tableName ||\n c.slug === activeTableData.tableName ||\n c.collectionId === activeTableData.tableName\n ) || null;\n }, [activeTableData, collectionRegistry.collections]);\n\n /** The category of the currently selected table. */\n const activeTableCategory = useMemo((): TableCategory | null => {\n if (!activeTableData) return null;\n const isMapped = !!activeCollection;\n return classifyTableClient(activeTableData.tableName, activeTableData.schemaName, junctionTableNames, isMapped);\n }, [activeTableData, activeCollection, junctionTableNames]);\n\n const mergedPolicies = useMemo(() => {\n if (!activeTableData) return [];\n\n const policiesMap: Record<string, PostgresPolicy> = {};\n\n // Load live policies\n (activeTableData.policies || []).forEach(p => {\n policiesMap[p.policyname] = { ...p,\nstatus: \"live\" };\n });\n\n // Merge code-based policies.\n //\n // A rule without an explicit `name` still produces policies — Postgres gets\n // `<table>_<op>_<hash>`, one per operation. Skipping those rules left their\n // live policies looking like hand-written SQL (\"DB Only\"), so derive the\n // names the generator would emit and match on those.\n if (activeCollection && isPostgresCollectionConfig(activeCollection) && activeCollection.securityRules) {\n activeCollection.securityRules.forEach((rule) => {\n const ops = getPolicyOperations(rule);\n const policyNames = getPolicyNamesForRule(rule, activeTableData.tableName);\n\n policyNames.forEach((policyName, opIdx) => {\n policiesMap[policyName] = {\n policyname: policyName,\n tablename: activeTableData.tableName,\n permissive: (rule.mode || \"permissive\").toUpperCase() as PostgresPolicy[\"permissive\"],\n cmd: (ops[opIdx] ?? rule.operation ?? \"ALL\").toUpperCase() as PostgresPolicy[\"cmd\"],\n roles: [...(rule.roles ?? [\"public\"])],\n qual: rule.using || null,\n with_check: rule.withCheck || null,\n // \"both\" = defined in code and live in Postgres (potentially edited)\n status: policiesMap[policyName] ? \"both\" : \"code_only\"\n };\n });\n });\n }\n\n // Junction tables have no collection, but their policies are generated\n // too — derived from the endpoints' relations. Recognise them so they\n // don't show as hand-written SQL (\"DB Only\"). If the registry's\n // collections don't carry resolvable relations, they simply stay \"live\".\n if (!activeCollection) {\n try {\n const registryCollections = (collectionRegistry.collections ?? []) as unknown as Parameters<typeof resolveJunctionSpecs>[0];\n const spec = resolveJunctionSpecs(registryCollections).get(activeTableData.tableName);\n if (spec) {\n const generatedNames = getPolicyNamesForRules(getJunctionSecurityRules(spec), spec.table);\n for (const p of Object.values(policiesMap)) {\n if (generatedNames.has(p.policyname)) p.status = \"both\";\n }\n }\n } catch {\n /* serialized configs without relation closures — leave as live */\n }\n }\n\n return Object.values(policiesMap).sort((a, b) => a.policyname.localeCompare(b.policyname));\n }, [activeTableData, activeCollection, collectionRegistry.collections]);\n\n // Stats for the info tab\n const rlsStats = useMemo(() => {\n const total = tables.length;\n const enabled = tables.filter(t => t.rlsEnabled).length;\n const withPolicies = tables.filter(t => t.policies.length > 0).length;\n const totalPolicies = tables.reduce((sum, t) => sum + t.policies.length, 0);\n return { total,\nenabled,\nwithPolicies,\ntotalPolicies };\n }, [tables]);\n\n const renderPolicyTag = (label: string, value: string) => {\n return (\n <div className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-surface-100 dark:bg-surface-950 border border-surface-200 dark:border-surface-700/50\">\n <span className=\"text-[10px] uppercase text-text-secondary dark:text-text-secondary-dark font-medium tracking-wider\">\n {label}:\n </span>\n <span className=\"font-mono text-xs text-text-primary dark:text-text-primary-dark break-all\">\n {value}\n </span>\n </div>\n );\n };\n\n return (\n <div className=\"flex h-full w-full bg-white dark:bg-surface-950 overflow-hidden text-text-primary dark:text-text-primary-dark\">\n <ResizablePanels\n orientation=\"horizontal\"\n panelSizePercent={sidebarSize}\n onPanelSizeChange={setSidebarSize}\n minPanelSizePx={220}\n firstPanel={\n <div className={cls(\"flex flex-col h-full w-full bg-white dark:bg-surface-950 border-r\", defaultBorderMixin)}>\n <Tabs value={sidebarTab} onValueChange={(v) => setSidebarTab(v as \"tables\" | \"info\")} variant=\"boxy\" className=\"border-b border-surface-200 dark:border-surface-950\">\n <Tab value=\"tables\">Tables</Tab>\n <Tab value=\"info\">Info</Tab>\n </Tabs>\n\n <div className=\"flex-grow overflow-hidden relative\">\n {sidebarTab === \"tables\" && (\n <div className=\"flex flex-col h-full\">\n <div className={cls(\"flex items-center justify-between px-3 py-2 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"font-bold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark\">\n {t(\"studio_schema_tables\")}\n </Typography>\n <IconButton size=\"small\" onClick={fetchRLSData} title=\"Refresh\">\n <RefreshCwIcon size={iconSize.smallest}/>\n </IconButton>\n </div>\n <div className=\"flex-grow overflow-y-auto no-scrollbar p-1\">\n {isLoading && tables.length === 0 ? (\n <div className=\"flex justify-center p-4\"><CircularProgress size=\"small\"/></div>\n ) : tables.length === 0 ? (\n <div className=\"p-4 text-center\">\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark italic\">{t(\"studio_rls_no_tables\")}</Typography>\n </div>\n ) : (\n <>\n {/* ── Schema Collections ── */}\n {categorizedTables.collection.length > 0 && (\n <SidebarSection\n title=\"Schema Collections\"\n icon={<DatabaseIcon size={12} className=\"text-primary dark:text-primary-light\"/>}\n expanded={expandedSections.collection ?? true}\n onToggle={() => setExpandedSections(prev => ({ ...prev, collection: !(prev.collection ?? true) }))}\n >\n {categorizedTables.collection.map(table => (\n <SidebarTableRow\n key={`${table.schemaName}.${table.tableName}`}\n table={table}\n isSelected={selectedTable === `${table.schemaName}.${table.tableName}`}\n onSelect={() => setSelectedTable(`${table.schemaName}.${table.tableName}`)}\n t={t}\n />\n ))}\n </SidebarSection>\n )}\n\n {/* ── Other Tables (unmapped + junction) ── */}\n {(categorizedTables.other.length > 0 || categorizedTables.junction.length > 0) && (\n <SidebarSection\n title=\"Other Tables\"\n icon={<AlertTriangleIcon size={12} className=\"text-yellow-500 dark:text-yellow-400\"/>}\n expanded={expandedSections.other ?? true}\n onToggle={() => setExpandedSections(prev => ({ ...prev, other: !(prev.other ?? true) }))}\n >\n {categorizedTables.other.map(table => (\n <SidebarTableRow\n key={`${table.schemaName}.${table.tableName}`}\n table={table}\n isSelected={selectedTable === `${table.schemaName}.${table.tableName}`}\n onSelect={() => setSelectedTable(`${table.schemaName}.${table.tableName}`)}\n t={t}\n />\n ))}\n {categorizedTables.junction.map(table => (\n <SidebarTableRow\n key={`${table.schemaName}.${table.tableName}`}\n table={table}\n isSelected={selectedTable === `${table.schemaName}.${table.tableName}`}\n onSelect={() => setSelectedTable(`${table.schemaName}.${table.tableName}`)}\n badge=\"Junction\"\n dimmed\n t={t}\n />\n ))}\n </SidebarSection>\n )}\n\n {/* ── Rebase Internal ── */}\n {categorizedTables.internal.length > 0 && (\n <SidebarSection\n title=\"Rebase Internal\"\n icon={<LockIcon size={12} className=\"text-text-disabled dark:text-text-disabled-dark\"/>}\n expanded={expandedSections.internal ?? false}\n onToggle={() => setExpandedSections(prev => ({ ...prev, internal: !(prev.internal ?? false) }))}\n count={categorizedTables.internal.length}\n >\n {categorizedTables.internal.map(table => (\n <SidebarTableRow\n key={`${table.schemaName}.${table.tableName}`}\n table={table}\n isSelected={selectedTable === `${table.schemaName}.${table.tableName}`}\n onSelect={() => setSelectedTable(`${table.schemaName}.${table.tableName}`)}\n dimmed\n t={t}\n />\n ))}\n </SidebarSection>\n )}\n </>\n )}\n </div>\n </div>\n )}\n\n {sidebarTab === \"info\" && (\n <div className=\"flex flex-col h-full\">\n <div className={cls(\"flex items-center justify-between px-3 py-2 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"font-bold uppercase tracking-wider text-text-disabled dark:text-text-disabled-dark\">\n Overview\n </Typography>\n </div>\n <div className=\"flex-grow overflow-y-auto p-3 space-y-3 no-scrollbar\">\n <div className={cls(\"p-3 rounded-lg border bg-white dark:bg-surface-900\", defaultBorderMixin)}>\n <div className=\"flex items-center gap-2 mb-2\">\n <ShieldIcon size={iconSize.smallest} className=\"text-primary\"/>\n <Typography variant=\"body2\" className=\"font-semibold text-[13px]\">RLS Studio</Typography>\n </div>\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark text-[11px] leading-relaxed block\">\n Manage Row Level Security policies for your PostgreSQL tables. Enable RLS and create fine-grained access policies.\n </Typography>\n </div>\n\n <div className=\"space-y-2\">\n <div className={cls(\"p-2.5 rounded border bg-white dark:bg-surface-900 flex items-center justify-between\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark text-[11px]\">Total tables</Typography>\n <Typography variant=\"body2\" className=\"font-mono text-[13px] font-medium\">{rlsStats.total}</Typography>\n </div>\n <div className={cls(\"p-2.5 rounded border bg-white dark:bg-surface-900 flex items-center justify-between\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark text-[11px]\">RLS enabled</Typography>\n <div className=\"flex items-center gap-1.5\">\n <div className=\"w-1.5 h-1.5 rounded-full bg-green-500\"/>\n <Typography variant=\"body2\" className=\"font-mono text-[13px] font-medium\">{rlsStats.enabled}</Typography>\n </div>\n </div>\n <div className={cls(\"p-2.5 rounded border bg-white dark:bg-surface-900 flex items-center justify-between\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark text-[11px]\">Tables with policies</Typography>\n <Typography variant=\"body2\" className=\"font-mono text-[13px] font-medium\">{rlsStats.withPolicies}</Typography>\n </div>\n <div className={cls(\"p-2.5 rounded border bg-white dark:bg-surface-900 flex items-center justify-between\", defaultBorderMixin)}>\n <Typography variant=\"caption\" className=\"text-text-secondary dark:text-text-secondary-dark text-[11px]\">Total policies</Typography>\n <Typography variant=\"body2\" className=\"font-mono text-[13px] font-medium\">{rlsStats.totalPolicies}</Typography>\n </div>\n </div>\n\n {/* Security health indicators */}\n {rlsStats.total - rlsStats.enabled > 0 && (\n <div className={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\", defaultBorderMixin)}>\n <AlertTriangleIcon size={14} className=\"text-yellow-600 dark:text-yellow-500 mt-0.5 shrink-0\"/>\n <div>\n <Typography variant=\"caption\" className=\"text-yellow-800 dark:text-yellow-400 text-[11px] font-semibold block\">\n {rlsStats.total - rlsStats.enabled} table{rlsStats.total - rlsStats.enabled > 1 ? \"s\" : \"\"} without RLS\n </Typography>\n <Typography variant=\"caption\" className=\"text-yellow-700 dark:text-yellow-600 text-[10px] block mt-0.5\">\n These tables have no row-level access control. If auth enforcement is disabled, data may be publicly accessible.\n </Typography>\n </div>\n </div>\n )}\n\n {rlsStats.enabled > 0 && rlsStats.enabled - rlsStats.withPolicies > 0 && (\n <div className={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\", defaultBorderMixin)}>\n <ShieldIcon size={14} className=\"text-blue-600 dark:text-blue-400 mt-0.5 shrink-0\"/>\n <div>\n <Typography variant=\"caption\" className=\"text-blue-800 dark:text-blue-300 text-[11px] font-semibold block\">\n {rlsStats.enabled - rlsStats.withPolicies} table{rlsStats.enabled - rlsStats.withPolicies > 1 ? \"s\" : \"\"} with RLS but no policies\n </Typography>\n <Typography variant=\"caption\" className=\"text-blue-700 dark:text-blue-500 text-[10px] block mt-0.5\">\n RLS is enabled but no permissive policies exist. All access is denied by default (Postgres deny-all).\n </Typography>\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n }\n secondPanel={\n <div className=\"flex-grow flex flex-col min-w-0 h-full w-full bg-white dark:bg-surface-950\">\n {/* Toolbar Header matching SQL/JS Editor style */}\n <div className={cls(\"flex items-center justify-between pr-2 border-b bg-white dark:bg-surface-950 min-h-[46px]\", defaultBorderMixin)}>\n <div className=\"flex items-center flex-grow overflow-hidden px-4\">\n <Typography variant=\"subtitle2\" className=\"font-mono text-text-secondary dark:text-text-secondary-dark truncate\">\n {activeTableData ? `${activeTableData.schemaName}.${activeTableData.tableName}` : t(\"studio_rls_select_table\")}\n </Typography>\n {activeTableData && (\n <div className=\"ml-3\">\n {activeTableData.rlsEnabled ? (\n <Chip size=\"smallest\" className=\"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400 border-green-200 dark:border-green-800\">{t(\"studio_rls_enabled\")}</Chip>\n ) : (\n <Chip size=\"smallest\" className=\"bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400 border-yellow-200 dark:border-yellow-800\">{t(\"studio_rls_disabled\")}</Chip>\n )}\n </div>\n )}\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-1.5\">\n {activeTableData && (\n <>\n <Button\n variant=\"text\"\n size=\"small\"\n onClick={async () => {\n const table = activeTableData.tableName;\n const qualifiedTable = `${sanitizeSqlIdentifier(activeTableData.schemaName)}.${sanitizeSqlIdentifier(table)}`;\n const action = activeTableData.rlsEnabled ? \"DISABLE\" : \"ENABLE\";\n if (!confirm(`Are you sure you want to ${action.toLowerCase()} Row Level Security on \"${table}\"?`)) return;\n try {\n await databaseAdmin!.executeSql!(`ALTER TABLE ${qualifiedTable} ${action} ROW LEVEL SECURITY`);\n snackbarController.open({ type: \"success\",\nmessage: `RLS ${action.toLowerCase()}d on ${table}` });\n fetchRLSData();\n } catch (e: unknown) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n }}\n >\n {activeTableData.rlsEnabled ? t(\"studio_rls_disable_rls\") : t(\"studio_rls_enable_rls\")}\n </Button>\n\n <div className=\"h-4 w-px bg-surface-200 dark:bg-surface-950 mx-1\"/>\n\n <Button\n variant=\"text\"\n size=\"small\"\n onClick={fetchRLSData}\n startIcon={<RefreshCwIcon size={iconSize.smallest}/>}\n >\n Refresh\n </Button>\n\n <div className=\"h-4 w-px bg-surface-200 dark:bg-surface-950 mx-1\"/>\n\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={() => setEditingPolicy(\"new\")}\n >\n {t(\"studio_rls_create_policy\")}\n </Button>\n </>\n )}\n </div>\n </div>\n\n {isLoading && !activeTableData ? (\n <div className=\"flex-grow flex items-center justify-center h-full\">\n <CircularProgress size=\"small\"/>\n </div>\n ) : error ? (\n <div className=\"p-6 h-full flex items-center justify-center\">\n <ErrorView title={t(\"studio_rls_error\")} error={error} onRetry={fetchRLSData}/>\n </div>\n ) : !activeTableData ? (\n <div className=\"flex-grow flex items-center justify-center text-text-disabled h-full\">\n <div className=\"text-center\">\n <svg className=\"w-12 h-12 mx-auto mb-4 opacity-50\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><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\"/></svg>\n <Typography variant=\"body2\">{t(\"studio_rls_select_table\")}</Typography>\n </div>\n </div>\n ) : editingPolicy ? (\n <PolicyEditor\n policy={editingPolicy === \"new\" ? undefined : editingPolicy}\n schema={activeTableData.schemaName}\n table={activeTableData.tableName}\n onSave={async (newPolicy) => {\n if (activeCollection) {\n // Collection-mapped table: save via schema-editor API\n const rule: Record<string, unknown> = {\n name: newPolicy.policyname,\n operation: newPolicy.cmd?.toLowerCase(),\n mode: newPolicy.permissive?.toLowerCase(),\n using: newPolicy.qual || undefined,\n withCheck: newPolicy.with_check || undefined,\n roles: newPolicy.roles\n };\n\n const existingRules = (isPostgresCollectionConfig(activeCollection) ? activeCollection.securityRules : undefined) || [];\n let newRules;\n if (editingPolicy === \"new\") {\n newRules = [...existingRules, rule];\n } else {\n newRules = existingRules.map((r: { name?: string }) => r.name === editingPolicy.policyname ? rule : r);\n }\n\n try {\n const response = await fetch(`${apiUrl}/api/schema-editor/collection/save`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n collectionId: (activeCollection as { id?: string, path?: string, alias?: string }).id || (activeCollection as { id?: string, path?: string, alias?: string }).path || (activeCollection as { id?: string, path?: string, alias?: string }).alias || activeTableData.tableName,\n collectionData: { securityRules: newRules }\n })\n });\n if (!response.ok) throw new Error(\"Failed to save policy\");\n\n snackbarController.open({ type: \"success\",\nmessage: \"Policy saved successfully\" });\n setEditingPolicy(null);\n fetchRLSData();\n } catch (e: unknown) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n } else {\n // Non-collection table (internal/junction/unmapped): apply policy directly via SQL\n try {\n const qualifiedTable = `${sanitizeSqlIdentifier(activeTableData.schemaName)}.${sanitizeSqlIdentifier(activeTableData.tableName)}`;\n const policyName = sanitizeSqlIdentifier(newPolicy.policyname || \"unnamed_policy\");\n const cmd = newPolicy.cmd || \"ALL\";\n const permissive = (newPolicy.permissive || \"PERMISSIVE\") === \"PERMISSIVE\" ? \"PERMISSIVE\" : \"RESTRICTIVE\";\n const roles = newPolicy.roles && newPolicy.roles.length > 0\n ? newPolicy.roles.map(r => sanitizeSqlIdentifier(r)).join(\", \")\n : \"public\";\n\n // Drop existing policy if editing\n if (editingPolicy !== \"new\") {\n await databaseAdmin!.executeSql!(`DROP POLICY IF EXISTS ${policyName} ON ${qualifiedTable}`);\n }\n\n let sql = `CREATE POLICY ${policyName} ON ${qualifiedTable}`;\n sql += ` AS ${permissive}`;\n sql += ` FOR ${cmd}`;\n sql += ` TO ${roles}`;\n if (newPolicy.qual) sql += ` USING (${newPolicy.qual})`;\n if (newPolicy.with_check) sql += ` WITH CHECK (${newPolicy.with_check})`;\n\n await databaseAdmin!.executeSql!(sql);\n\n snackbarController.open({ type: \"success\",\nmessage: `Policy \"${newPolicy.policyname}\" applied directly via SQL` });\n setEditingPolicy(null);\n fetchRLSData();\n } catch (e: unknown) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n }\n }}\n onCancel={() => setEditingPolicy(null)}\n />\n ) : (\n <div className=\"flex-grow flex flex-col overflow-hidden\">\n <div className=\"p-6 pt-4 flex-grow overflow-auto bg-surface-50 dark:bg-surface-900\">\n <div className=\"max-w-4xl mx-auto flex flex-col gap-6\">\n {/* Context-aware banner based on table category */}\n {activeTableData && activeTableCategory === \"internal\" && (\n <Alert color=\"info\">\n <div className=\"flex items-start gap-2\">\n <LockIcon size={16} className=\"shrink-0 mt-0.5\"/>\n <div>\n <Typography variant=\"body2\" className=\"mb-1 font-semibold\">\n Rebase System Table\n </Typography>\n <Typography variant=\"caption\" className=\"opacity-80\">\n This table is managed internally by Rebase. Its security policies are configured automatically.\n Editing policies on system tables is an advanced operation.\n </Typography>\n </div>\n </div>\n </Alert>\n )}\n {activeTableData && activeTableCategory === \"junction\" && (\n <Alert color=\"info\">\n <div className=\"flex items-start gap-2\">\n <Link2Icon size={16} className=\"shrink-0 mt-0.5\"/>\n <div>\n <Typography variant=\"body2\" className=\"mb-1 font-semibold\">\n Junction Table\n </Typography>\n <Typography variant=\"caption\" className=\"opacity-80\">\n This is an auto-generated junction table for a many-to-many relation.\n Rebase derives its policies: rows are readable when both related rows\n are, and writable following the declaring collection&apos;s update rules\n (plus the server/admin baseline). You can still add RLS policies\n directly to broaden access.\n </Typography>\n </div>\n </div>\n </Alert>\n )}\n {activeTableData && activeTableCategory === \"other\" && (\n <Alert color=\"warning\">\n <div className=\"flex items-start gap-2\">\n <AlertTriangleIcon size={16} className=\"shrink-0 mt-0.5\"/>\n <div>\n <Typography variant=\"body2\" className=\"mb-1 font-semibold\">\n Unmapped Table\n </Typography>\n <Typography variant=\"caption\" className=\"opacity-80\">\n This table exists in the database but isn&apos;t mapped to a collection definition.\n Import it into a Schema configuration file to manage security policies visually.\n </Typography>\n </div>\n </div>\n </Alert>\n )}\n\n {activeTableData && !activeTableData.rlsEnabled && (\n <div className={cls(\"p-4 sm:p-5 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-900/50 rounded-lg flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between\", defaultBorderMixin)}>\n <div className=\"flex gap-3 items-start\">\n <div className=\"mt-1 bg-yellow-100 dark:bg-yellow-900/50 p-1.5 rounded-md shrink-0 flex items-center justify-center\">\n <AlertTriangleIcon size={iconSize.smallest}/>\n </div>\n <div>\n <Typography variant=\"subtitle2\" className=\"text-yellow-800 dark:text-yellow-500\">\n Row Level Security (RLS) is disabled\n </Typography>\n <Typography variant=\"body2\" className=\"text-yellow-700 dark:text-yellow-600/90 mt-1 max-w-2xl\">\n Your table is completely readable and writable by anyone with access privileges. Enable RLS to create policies that restrict access to specific rows.\n </Typography>\n </div>\n </div>\n <Button\n size=\"medium\"\n variant=\"filled\"\n color=\"neutral\"\n onClick={() => setEditingPolicy(\"new\")}\n className=\"shrink-0 whitespace-nowrap\"\n disabled={!activeCollection}\n >\n {t(\"studio_rls_create_policy\")}\n </Button>\n </div>\n )}\n\n {activeTableData && mergedPolicies && mergedPolicies.length > 0 && (\n <div className=\"flex flex-col gap-3\">\n <Typography variant=\"subtitle2\" className=\"text-text-secondary dark:text-text-secondary-dark uppercase tracking-wider mb-1\">{t(\"studio_rls_policies\")}</Typography>\n {mergedPolicies.map(policy => (\n <Paper key={policy.policyname} className={cls(\"p-3 sm:px-4 sm:py-3 flex flex-col sm:flex-row sm:items-center justify-between gap-4 border rounded-lg\", defaultBorderMixin)}>\n <div className=\"flex flex-col gap-2 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <KeyIcon size={iconSize.smallest} className=\"text-text-secondary dark:text-text-secondary-dark shrink-0\"/>\n <Typography variant=\"body2\" className=\"truncate\">{policy.policyname}</Typography>\n {policy.status === \"code_only\" && (\n <Tooltip title=\"This policy is defined in your code but hasn't been applied to the database yet.\">\n <div className=\"px-1.5 py-0.5 rounded text-[10px] uppercase bg-primary/10 text-primary border border-primary/20 shrink-0\">\n Unapplied\n </div>\n </Tooltip>\n )}\n {policy.status === \"live\" && (\n <Tooltip title=\"This policy is live in the database but missing from your codebase schema.\">\n <div className=\"px-1.5 py-0.5 rounded text-[10px] uppercase bg-orange-500/10 text-orange-600 border border-orange-500/20 shrink-0\">\n DB Only\n </div>\n </Tooltip>\n )}\n </div>\n <div className=\"flex flex-wrap gap-1.5 text-sm\">\n {renderPolicyTag(\"Action\", policy.cmd)}\n {renderPolicyTag(\"Roles\", Array.isArray(policy.roles) ? policy.roles.join(\", \") : policy.roles)}\n </div>\n </div>\n <div className=\"flex gap-2 shrink-0 items-center\">\n {policy.status === \"live\" && activeCollection && (\n <Button\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n onClick={async () => {\n const rule: Record<string, unknown> = {\n name: policy.policyname,\n operation: policy.cmd?.toLowerCase(),\n mode: policy.permissive?.toLowerCase(),\n using: policy.qual || undefined,\n withCheck: policy.with_check || undefined,\n roles: policy.roles\n };\n\n const existingRules = (isPostgresCollectionConfig(activeCollection) ? activeCollection.securityRules : undefined) || [];\n const newRules = [...existingRules, rule];\n\n try {\n const response = await fetch(`${apiUrl}/api/schema-editor/collection/save`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n collectionId: (activeCollection as { id?: string, path?: string, alias?: string }).id || (activeCollection as { id?: string, path?: string, alias?: string }).path || (activeCollection as { id?: string, path?: string, alias?: string }).alias || activeTableData!.tableName,\n collectionData: { securityRules: newRules }\n })\n });\n if (!response.ok) throw new Error(\"Failed to save policy\");\n\n snackbarController.open({ type: \"success\",\nmessage: \"Policy imported successfully\" });\n fetchRLSData();\n } catch (e: unknown) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n }}\n >\n Import to codebase\n </Button>\n )}\n <Button size=\"small\" variant=\"text\" color=\"primary\" onClick={() => setEditingPolicy(policy)}>\n {t(\"studio_rls_edit\")}\n </Button>\n {policy.status !== \"code_only\" && (\n <Tooltip title={t(\"studio_rls_delete\")} asChild={true}>\n <IconButton\n size=\"small\"\n onClick={async () => {\n const table = activeTableData!.tableName;\n const qualifiedTable = `${sanitizeSqlIdentifier(activeTableData!.schemaName)}.${sanitizeSqlIdentifier(table)}`;\n if (!confirm(`Drop policy \"${policy.policyname}\" from table \"${table}\"?`)) return;\n try {\n await databaseAdmin!.executeSql!(`DROP POLICY ${sanitizeSqlIdentifier(policy.policyname)} ON ${qualifiedTable}`);\n snackbarController.open({ type: \"success\",\nmessage: `Policy \"${policy.policyname}\" dropped` });\n fetchRLSData();\n } catch (e: unknown) {\n snackbarController.open({ type: \"error\",\nmessage: e instanceof Error ? e.message : String(e) });\n }\n }}\n >\n <Trash2Icon size={iconSize.smallest}/>\n </IconButton>\n </Tooltip>\n )}\n </div>\n </Paper>\n ))}\n </div>\n )}\n\n {activeTableData && mergedPolicies.length === 0 && activeTableData.rlsEnabled && (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <ShieldIcon size={40} className=\"text-surface-300 dark:text-surface-600 mb-4\"/>\n <Typography variant=\"subtitle2\" className=\"text-text-secondary dark:text-text-secondary-dark mb-2\">\n No policies defined\n </Typography>\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark max-w-sm mb-4\">\n 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.\n </Typography>\n <Button\n size=\"small\"\n variant=\"filled\"\n color=\"primary\"\n onClick={() => setEditingPolicy(\"new\")}\n >\n {t(\"studio_rls_create_policy\")}\n </Button>\n </div>\n )}\n\n {activeTableData && mergedPolicies.length === 0 && !activeTableData.rlsEnabled && activeCollection && (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <AlertTriangleIcon size={40} className=\"text-yellow-400 dark:text-yellow-600 mb-4\"/>\n <Typography variant=\"subtitle2\" className=\"text-text-secondary dark:text-text-secondary-dark mb-2\">\n No access control\n </Typography>\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark max-w-sm\">\n This table has neither RLS nor policies. Enable RLS and create policies to restrict row-level access.\n </Typography>\n </div>\n )}\n\n </div>\n </div>\n </div>\n )}\n </div>\n }\n />\n </div>\n );\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as MonacoEditor } from "./MonacoEditor-COZqrIJ1.js";
2
- import { ConfirmationDialog, ErrorView, IconForView, useRebaseContext, useSnackbarController, useStudioCollectionRegistry, useStudioSideEntityController, useTranslation } from "@rebasepro/core";
1
+ import { t as MonacoEditor } from "./MonacoEditor-D0_QljcX.js";
2
+ import { ConfirmationDialog, ErrorView, IconForView, useRebaseContext, useSnackbarController, useStudioCollectionRegistry, useStudioSidePanelController, useTranslation } from "@rebasepro/app";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { Button, Checkbox, CircularProgress, Collapse, CopyIcon, DatabaseIcon, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Menu, MenuIcon, MenuItem, MoreVerticalIcon, PencilIcon, PlayIcon, PlusIcon, RefreshCwIcon, ResizablePanels, Tab, Tabs, TerminalIcon, TextField, TextareaAutosize, Tooltip, Trash2Icon, Typography, VirtualTable, XIcon, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -104,7 +104,7 @@ var SchemaBrowser = ({ onTableClick, schemas, isSchemaLoading, schemaError, onRe
104
104
  e.stopPropagation();
105
105
  navigator.clipboard.writeText(table.tableName);
106
106
  },
107
- title: "CopyIcon table name",
107
+ title: "Copy table name",
108
108
  children: /* @__PURE__ */ jsx(CopyIcon, { size: iconSize.small })
109
109
  }),
110
110
  /* @__PURE__ */ jsxs(Menu, {
@@ -201,7 +201,7 @@ var SchemaBrowser = ({ onTableClick, schemas, isSchemaLoading, schemaError, onRe
201
201
  e.stopPropagation();
202
202
  navigator.clipboard.writeText(col.name);
203
203
  },
204
- title: "CopyIcon column name",
204
+ title: "Copy column name",
205
205
  children: /* @__PURE__ */ jsx(CopyIcon, { size: iconSize.smallest })
206
206
  })
207
207
  ]
@@ -765,7 +765,7 @@ var getStoragePrefix = (baseUrl) => {
765
765
  };
766
766
  var SQLEditor = () => {
767
767
  const { databaseAdmin, client } = useRebaseContext();
768
- const sideEntityController = useStudioSideEntityController();
768
+ const sidePanelController = useStudioSidePanelController();
769
769
  const snackbarController = useSnackbarController();
770
770
  const collectionRegistry = useStudioCollectionRegistry();
771
771
  const { t } = useTranslation();
@@ -1527,7 +1527,7 @@ var SQLEditor = () => {
1527
1527
  className: "text-surface-400 dark:text-surface-500 hover:text-surface-600 dark:hover:text-surface-300 transition-colors",
1528
1528
  onClick: (e) => {
1529
1529
  e.stopPropagation();
1530
- sideEntityController?.open({
1530
+ sidePanelController?.open({
1531
1531
  path: ra.collection.collection.slug,
1532
1532
  entityId: ra.entityId,
1533
1533
  collection: ra.collection.collection,
@@ -1551,7 +1551,7 @@ var SQLEditor = () => {
1551
1551
  children: rowActions.map((ra) => /* @__PURE__ */ jsx(MenuItem, {
1552
1552
  dense: true,
1553
1553
  onClick: () => {
1554
- sideEntityController?.open({
1554
+ sidePanelController?.open({
1555
1555
  path: ra.collection.collection.slug,
1556
1556
  entityId: ra.entityId,
1557
1557
  collection: ra.collection.collection,
@@ -1961,4 +1961,4 @@ var SQLEditor = () => {
1961
1961
  //#endregion
1962
1962
  export { SQLEditor };
1963
1963
 
1964
- //# sourceMappingURL=SQLEditor-CuAhR-zr.js.map
1964
+ //# sourceMappingURL=SQLEditor-_dCqVAN_.js.map