@rebasepro/studio 0.13.0 → 0.13.1-canary.g18cfeb7

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.
@@ -3,7 +3,7 @@ import { ConfirmationDialog, ErrorView, IconForView, useRebaseContext, useSnackb
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";
6
- import { toSnakeCase } from "@rebasepro/utils";
6
+ import { isArrayValue, isRecordValue, readStoredJson, readStoredString, toSnakeCase, writeStoredJson, writeStoredString } from "@rebasepro/utils";
7
7
  import { createPortal } from "react-dom";
8
8
  import { parseFirst } from "pgsql-ast-parser";
9
9
  //#region src/components/SQLEditor/SchemaBrowser.tsx
@@ -763,6 +763,16 @@ var getStoragePrefix = (baseUrl) => {
763
763
  if (!baseUrl) return "default";
764
764
  return baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_");
765
765
  };
766
+ /**
767
+ * Whether a stored entry is a tab this release can restore. Storage holds
768
+ * whatever the last version to run wrote, so the fields are checked rather
769
+ * than assumed.
770
+ */
771
+ function isStoredTab(value) {
772
+ if (typeof value !== "object" || value === null) return false;
773
+ const tab = value;
774
+ return typeof tab.id === "string" && typeof tab.name === "string" && typeof tab.sql === "string";
775
+ }
766
776
  var SQLEditor = () => {
767
777
  const { databaseAdmin, client } = useRebaseContext();
768
778
  const sidePanelController = useStudioSidePanelController();
@@ -775,21 +785,21 @@ var SQLEditor = () => {
775
785
  const schemaFetchedRef = useRef(false);
776
786
  const [schemaError, setSchemaError] = useState(null);
777
787
  const [selectedDatabase, setSelectedDatabase] = useState(() => {
778
- const projectPrefixSync = client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default";
779
- return localStorage.getItem(`rebase_sql_selected_db_${projectPrefixSync}`) || void 0;
788
+ return readStoredString(`rebase_sql_selected_db_${client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default"}`) || void 0;
780
789
  });
781
790
  const [selectedRole, setSelectedRole] = useState(() => {
782
- const projectPrefixSync = client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default";
783
- return localStorage.getItem(`rebase_sql_selected_role_${projectPrefixSync}`) || void 0;
791
+ return readStoredString(`rebase_sql_selected_role_${client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default"}`) || void 0;
784
792
  });
785
793
  const [availableDatabases, setAvailableDatabases] = useState([]);
786
794
  const [availableRoles, setAvailableRoles] = useState([]);
787
795
  const [isLoadingConfig, setIsLoadingConfig] = useState(true);
788
796
  const [connectionConfigError, setConnectionConfigError] = useState(null);
789
797
  const [tabs, setTabs] = useState(() => {
790
- const projectPrefixSync = client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default";
791
- const saved = localStorage.getItem(`rebase_sql_tabs_${projectPrefixSync}`);
792
- if (saved) return JSON.parse(saved).map((t) => ({
798
+ const projectPrefixSync = getStoragePrefix(client?.baseUrl);
799
+ const restored = readStoredJson(`rebase_sql_tabs_${projectPrefixSync}`, {
800
+ fallback: [],
801
+ accept: isArrayValue
802
+ }).filter(isStoredTab).map((t) => ({
793
803
  ...t,
794
804
  results: null,
795
805
  loading: false,
@@ -797,12 +807,13 @@ var SQLEditor = () => {
797
807
  execTime: null,
798
808
  lastExecutedSql: null
799
809
  }));
810
+ if (restored.length > 0) return restored;
800
811
  return [{
801
812
  id: "1",
802
813
  name: "Query 1",
803
814
  sql: "SELECT * FROM ",
804
- database: localStorage.getItem(`rebase_sql_selected_db_${projectPrefixSync}`) || void 0,
805
- role: localStorage.getItem(`rebase_sql_selected_role_${projectPrefixSync}`) || void 0,
815
+ database: readStoredString(`rebase_sql_selected_db_${projectPrefixSync}`) || void 0,
816
+ role: readStoredString(`rebase_sql_selected_role_${projectPrefixSync}`) || void 0,
806
817
  results: null,
807
818
  loading: false,
808
819
  error: null,
@@ -811,8 +822,7 @@ var SQLEditor = () => {
811
822
  }];
812
823
  });
813
824
  const [activeTabId, setActiveTabId] = useState(() => {
814
- const projectPrefixSync = client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default";
815
- return localStorage.getItem(`rebase_sql_active_tab_${projectPrefixSync}`) || "1";
825
+ return readStoredString(`rebase_sql_active_tab_${client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default"}`) || "1";
816
826
  });
817
827
  const activeTab = tabs.find((t) => t.id === activeTabId) || tabs[0];
818
828
  const updateActiveTab = useCallback((update) => {
@@ -845,21 +855,19 @@ var SQLEditor = () => {
845
855
  if (mounted) {
846
856
  setAvailableDatabases(dbs);
847
857
  setAvailableRoles(roles);
848
- const loadedDb = localStorage.getItem(`rebase_sql_selected_db_${projectPrefix}`) || void 0;
849
- const loadedRole = localStorage.getItem(`rebase_sql_selected_role_${projectPrefix}`) || void 0;
850
- const initialActiveTabId = localStorage.getItem(`rebase_sql_active_tab_${projectPrefix}`) || "1";
851
- let initialTabs = [];
852
- try {
853
- const savedTabs = localStorage.getItem(`rebase_sql_tabs_${projectPrefix}`);
854
- if (savedTabs) initialTabs = JSON.parse(savedTabs);
855
- } catch (e) {}
856
- const currentActiveTab = initialTabs.find((t) => t.id === initialActiveTabId);
858
+ const loadedDb = readStoredString(`rebase_sql_selected_db_${projectPrefix}`) || void 0;
859
+ const loadedRole = readStoredString(`rebase_sql_selected_role_${projectPrefix}`) || void 0;
860
+ const initialActiveTabId = readStoredString(`rebase_sql_active_tab_${projectPrefix}`) || "1";
861
+ const currentActiveTab = readStoredJson(`rebase_sql_tabs_${projectPrefix}`, {
862
+ fallback: [],
863
+ accept: isArrayValue
864
+ }).find((t) => t.id === initialActiveTabId);
857
865
  let actualDb = currentActiveTab?.database || loadedDb;
858
866
  if (actualDb && !dbs.includes(actualDb)) actualDb = void 0;
859
867
  if (!actualDb && dbs.length > 0) actualDb = currentDbFromApi && dbs.includes(currentDbFromApi) ? currentDbFromApi : dbs[0];
860
868
  if (actualDb) {
861
869
  setSelectedDatabase(actualDb);
862
- localStorage.setItem(`rebase_sql_selected_db_${projectPrefix}`, actualDb);
870
+ writeStoredString(`rebase_sql_selected_db_${projectPrefix}`, actualDb);
863
871
  setTabs((prev) => prev.map((t) => t.id === initialActiveTabId && (!t.database || !dbs.includes(t.database)) ? {
864
872
  ...t,
865
873
  database: actualDb
@@ -872,7 +880,7 @@ var SQLEditor = () => {
872
880
  else actualRole = roles.includes("postgres") ? "postgres" : roles[0];
873
881
  if (actualRole) {
874
882
  setSelectedRole(actualRole);
875
- localStorage.setItem(`rebase_sql_selected_role_${projectPrefix}`, actualRole);
883
+ writeStoredString(`rebase_sql_selected_role_${projectPrefix}`, actualRole);
876
884
  setTabs((prev) => prev.map((t) => t.id === initialActiveTabId && (!t.role || !roles.includes(t.role)) ? {
877
885
  ...t,
878
886
  role: actualRole
@@ -896,7 +904,7 @@ var SQLEditor = () => {
896
904
  }, [databaseAdmin, projectPrefix]);
897
905
  const handleDatabaseChange = (db, tabId) => {
898
906
  setSelectedDatabase(db);
899
- localStorage.setItem(`rebase_sql_selected_db_${projectPrefix}`, db);
907
+ writeStoredString(`rebase_sql_selected_db_${projectPrefix}`, db);
900
908
  setTabs((prev) => prev.map((t) => t.id === (tabId || activeTabId) ? {
901
909
  ...t,
902
910
  database: db
@@ -905,7 +913,7 @@ var SQLEditor = () => {
905
913
  };
906
914
  const handleRoleChange = (role, tabId) => {
907
915
  setSelectedRole(role);
908
- localStorage.setItem(`rebase_sql_selected_role_${projectPrefix}`, role);
916
+ writeStoredString(`rebase_sql_selected_role_${projectPrefix}`, role);
909
917
  setTabs((prev) => prev.map((t) => t.id === (tabId || activeTabId) ? {
910
918
  ...t,
911
919
  role
@@ -917,7 +925,7 @@ var SQLEditor = () => {
917
925
  if (newTab) {
918
926
  if (newTab.database && newTab.database !== selectedDatabase) {
919
927
  setSelectedDatabase(newTab.database);
920
- localStorage.setItem(`rebase_sql_selected_db_${projectPrefix}`, newTab.database);
928
+ writeStoredString(`rebase_sql_selected_db_${projectPrefix}`, newTab.database);
921
929
  schemaFetchedRef.current = false;
922
930
  } else if (!newTab.database && selectedDatabase) setTabs((prev) => prev.map((t) => t.id === newTabId ? {
923
931
  ...t,
@@ -925,7 +933,7 @@ var SQLEditor = () => {
925
933
  } : t));
926
934
  if (newTab.role && newTab.role !== selectedRole) {
927
935
  setSelectedRole(newTab.role);
928
- localStorage.setItem(`rebase_sql_selected_role_${projectPrefix}`, newTab.role);
936
+ writeStoredString(`rebase_sql_selected_role_${projectPrefix}`, newTab.role);
929
937
  } else if (!newTab.role && selectedRole) setTabs((prev) => prev.map((t) => t.id === newTabId ? {
930
938
  ...t,
931
939
  role: selectedRole
@@ -1128,21 +1136,24 @@ var SQLEditor = () => {
1128
1136
  selectedRole
1129
1137
  ]);
1130
1138
  const [columnWidths, setColumnWidths] = useState(() => {
1131
- const projectPrefixSync = client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default";
1132
- const saved = localStorage.getItem(`rebase_sql_column_widths_${projectPrefixSync}`);
1133
- return saved ? JSON.parse(saved) : {};
1139
+ return readStoredJson(`rebase_sql_column_widths_${client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default"}`, {
1140
+ fallback: {},
1141
+ accept: isRecordValue
1142
+ });
1134
1143
  });
1135
1144
  const [snippets, setSnippets] = useState([]);
1136
1145
  const [history, setHistory] = useState([]);
1137
1146
  const [isSaveDialogOpen, setIsSaveDialogOpen] = useState(false);
1138
1147
  const [newSnippetName, setNewSnippetName] = useState("");
1139
1148
  useEffect(() => {
1140
- const savedSnippets = localStorage.getItem(`rebase_sql_snippets_${projectPrefix}`);
1141
- if (savedSnippets) setSnippets(JSON.parse(savedSnippets));
1142
- else setSnippets([]);
1143
- const savedHistory = localStorage.getItem(`rebase_sql_history_${projectPrefix}`);
1144
- if (savedHistory) setHistory(JSON.parse(savedHistory));
1145
- else setHistory([]);
1149
+ setSnippets(readStoredJson(`rebase_sql_snippets_${projectPrefix}`, {
1150
+ fallback: [],
1151
+ accept: isArrayValue
1152
+ }));
1153
+ setHistory(readStoredJson(`rebase_sql_history_${projectPrefix}`, {
1154
+ fallback: [],
1155
+ accept: isArrayValue
1156
+ }));
1146
1157
  }, [projectPrefix]);
1147
1158
  useEffect(() => {
1148
1159
  const sanitizedTabs = tabs.map((t) => ({
@@ -1152,18 +1163,18 @@ var SQLEditor = () => {
1152
1163
  database: t.database,
1153
1164
  role: t.role
1154
1165
  }));
1155
- localStorage.setItem(`rebase_sql_tabs_${projectPrefix}`, JSON.stringify(sanitizedTabs));
1166
+ writeStoredJson(`rebase_sql_tabs_${projectPrefix}`, sanitizedTabs);
1156
1167
  }, [tabs, projectPrefix]);
1157
1168
  useEffect(() => {
1158
- localStorage.setItem(`rebase_sql_active_tab_${projectPrefix}`, activeTabId);
1169
+ writeStoredString(`rebase_sql_active_tab_${projectPrefix}`, activeTabId);
1159
1170
  }, [activeTabId, projectPrefix]);
1160
1171
  const saveSnippets = (newSnippets) => {
1161
1172
  setSnippets(newSnippets);
1162
- localStorage.setItem(`rebase_sql_snippets_${projectPrefix}`, JSON.stringify(newSnippets));
1173
+ writeStoredJson(`rebase_sql_snippets_${projectPrefix}`, newSnippets);
1163
1174
  };
1164
1175
  const saveHistory = (newHistory) => {
1165
1176
  setHistory(newHistory);
1166
- localStorage.setItem(`rebase_sql_history_${projectPrefix}`, JSON.stringify(newHistory.slice(-50)));
1177
+ writeStoredJson(`rebase_sql_history_${projectPrefix}`, newHistory.slice(-50));
1167
1178
  };
1168
1179
  const handleDeleteSnippet = (id) => {
1169
1180
  saveSnippets(snippets.filter((s) => s.id !== id));
@@ -1213,7 +1224,7 @@ var SQLEditor = () => {
1213
1224
  [key]: width
1214
1225
  }
1215
1226
  };
1216
- localStorage.setItem(`rebase_sql_column_widths_${projectPrefix}`, JSON.stringify(newWidths));
1227
+ writeStoredJson(`rebase_sql_column_widths_${projectPrefix}`, newWidths);
1217
1228
  return newWidths;
1218
1229
  });
1219
1230
  }, [activeTab.sql, projectPrefix]);
@@ -1654,33 +1665,18 @@ var SQLEditor = () => {
1654
1665
  ]
1655
1666
  });
1656
1667
  };
1657
- const [sidebarSize, setSidebarSize] = useState(() => {
1658
- try {
1659
- const projectPrefixSync = client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default";
1660
- const saved = localStorage.getItem(`rebase_sql_editor_sidebar_size_${projectPrefixSync}`);
1661
- return saved !== null ? parseFloat(saved) : 20;
1662
- } catch (e) {
1663
- return 20;
1664
- }
1665
- });
1666
- const [editorHeight, setEditorHeight] = useState(() => {
1667
- try {
1668
- const projectPrefixSync = client?.baseUrl ? client.baseUrl.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9]/g, "_") : "default";
1669
- const saved = localStorage.getItem(`rebase_sql_editor_height_${projectPrefixSync}`);
1670
- return saved !== null ? parseFloat(saved) : 50;
1671
- } catch (e) {
1672
- return 50;
1673
- }
1674
- });
1668
+ const readStoredSize = (key, fallback) => {
1669
+ const saved = readStoredString(`${key}_${getStoragePrefix(client?.baseUrl)}`);
1670
+ const parsed = saved === null ? NaN : parseFloat(saved);
1671
+ return Number.isFinite(parsed) ? parsed : fallback;
1672
+ };
1673
+ const [sidebarSize, setSidebarSize] = useState(() => readStoredSize("rebase_sql_editor_sidebar_size", 20));
1674
+ const [editorHeight, setEditorHeight] = useState(() => readStoredSize("rebase_sql_editor_height", 50));
1675
1675
  useEffect(() => {
1676
- try {
1677
- localStorage.setItem(`rebase_sql_editor_sidebar_size_${projectPrefix}`, sidebarSize.toString());
1678
- } catch (e) {}
1676
+ writeStoredString(`rebase_sql_editor_sidebar_size_${projectPrefix}`, sidebarSize.toString());
1679
1677
  }, [sidebarSize, projectPrefix]);
1680
1678
  useEffect(() => {
1681
- try {
1682
- localStorage.setItem(`rebase_sql_editor_height_${projectPrefix}`, editorHeight.toString());
1683
- } catch (e) {}
1679
+ writeStoredString(`rebase_sql_editor_height_${projectPrefix}`, editorHeight.toString());
1684
1680
  }, [editorHeight, projectPrefix]);
1685
1681
  const activeSnippet = snippets.find((s) => s.sql === activeTab.sql);
1686
1682
  const isFavorite = activeSnippet?.isFavorite || false;
@@ -1973,4 +1969,4 @@ var SQLEditor = () => {
1973
1969
  //#endregion
1974
1970
  export { SQLEditor };
1975
1971
 
1976
- //# sourceMappingURL=SQLEditor-CL6DcGRM.js.map
1972
+ //# sourceMappingURL=SQLEditor-BmI0iIWK.js.map