diff --git a/.github/workflows/build-app-beta.yaml b/.github/workflows/build-app-beta.yaml index d465041ed..06912d0fc 100644 --- a/.github/workflows/build-app-beta.yaml +++ b/.github/workflows/build-app-beta.yaml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macOS-10.15, windows-2022, ubuntu-18.04] + os: [macOS-10.15, windows-2022, ubuntu-22.04] # os: [macOS-10.15] steps: @@ -46,7 +46,7 @@ jobs: run: | yarn fillPackagedPlugins - name: Install Snapcraft - if: matrix.os == 'ubuntu-18.04' + if: matrix.os == 'ubuntu-22.04' uses: samuelmeuli/action-snapcraft@v1 - name: Publish run: | @@ -66,7 +66,7 @@ jobs: APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - name: publishSnap - if: matrix.os == 'ubuntu-18.04' + if: matrix.os == 'ubuntu-22.04' run: | snapcraft upload --release=beta app/dist/*.snap env: diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index b62b0be7d..d981ec5c0 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -16,8 +16,8 @@ jobs: strategy: fail-fast: false matrix: - # os: [ubuntu-18.04, windows-2016] - os: [macOS-10.15, windows-2022, ubuntu-18.04] + # os: [ubuntu-22.04, windows-2016] + os: [macOS-10.15, windows-2022, ubuntu-22.04] steps: - name: Context @@ -52,7 +52,7 @@ jobs: run: | yarn fillPackagedPlugins - name: Install Snapcraft - if: matrix.os == 'ubuntu-18.04' + if: matrix.os == 'ubuntu-22.04' uses: samuelmeuli/action-snapcraft@v1 - name: Publish run: | @@ -76,7 +76,7 @@ jobs: yarn generatePadFile - name: publishSnap - if: matrix.os == 'ubuntu-18.04' + if: matrix.os == 'ubuntu-22.04' run: | snapcraft upload --release=stable app/dist/*.snap env: @@ -134,7 +134,7 @@ jobs: mv app/dist/dbgate-pad.xml artifacts/ || true - name: Copy latest-linux.yml - if: matrix.os == 'ubuntu-18.04' + if: matrix.os == 'ubuntu-22.04' run: | mv app/dist/latest-linux.yml artifacts/latest-linux.yml || true diff --git a/.github/workflows/build-docker.yaml b/.github/workflows/build-docker.yaml index 1764abab3..71a53a2df 100644 --- a/.github/workflows/build-docker.yaml +++ b/.github/workflows/build-docker.yaml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - os: [ubuntu-18.04] + os: [ubuntu-22.04] steps: - name: Context diff --git a/.github/workflows/build-npm.yaml b/.github/workflows/build-npm.yaml index a97e7873f..0beba0e94 100644 --- a/.github/workflows/build-npm.yaml +++ b/.github/workflows/build-npm.yaml @@ -20,7 +20,7 @@ jobs: strategy: matrix: - os: [ubuntu-18.04] + os: [ubuntu-22.04] steps: - name: Context diff --git a/app/icon512-mac.png b/app/icon512-mac.png new file mode 100644 index 000000000..daaa18a67 Binary files /dev/null and b/app/icon512-mac.png differ diff --git a/app/package.json b/app/package.json index b4a560057..6b2a0cfad 100644 --- a/app/package.json +++ b/app/package.json @@ -21,7 +21,7 @@ "afterSign": "electron-builder-notarize", "mac": { "category": "database", - "icon": "icon512.png", + "icon": "icon512-mac.png", "hardenedRuntime": true, "entitlements": "entitlements.mac.plist", "entitlementsInherit": "entitlements.mac.plist", diff --git a/misc/convert-icons.sh b/misc/convert-icons.sh index 6802e3750..6bb229cab 100755 --- a/misc/convert-icons.sh +++ b/misc/convert-icons.sh @@ -104,3 +104,6 @@ magick icon.png -resize 16x16! ../app/icons/16x16.png magick icon.png -resize 192x192! ../packages/web/public/logo192.png magick icon.png -resize 512x512! ../packages/web/public/logo512.png magick icon.png -define icon:auto-resize="256,128,96,64,48,32,16" ../packages/web/public/favicon.ico + +convert icon.png -resize 800x800 -background transparent -gravity center -extent 1000x1000 iconmac.png +magick composite iconmac.png macbg.png -resize 600x600! ../app/icon512-mac.png diff --git a/misc/iconmac.png b/misc/iconmac.png new file mode 100644 index 000000000..acff17a7b Binary files /dev/null and b/misc/iconmac.png differ diff --git a/misc/macbg.png b/misc/macbg.png new file mode 100644 index 000000000..9edd457c7 Binary files /dev/null and b/misc/macbg.png differ diff --git a/package.json b/package.json index 473910d39..181e7d4c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "5.2.4", + "version": "5.2.5-beta.14", "name": "dbgate-all", "workspaces": [ "packages/*", diff --git a/packages/web/public/dimensions.css b/packages/web/public/dimensions.css index bae4ed425..9da6b06b3 100644 --- a/packages/web/public/dimensions.css +++ b/packages/web/public/dimensions.css @@ -22,7 +22,6 @@ --dim-header-top: calc( var(--dim-titlebar-height) * var(--dim-visible-titlebar) + var(--dim-toolbar-height) * var(--dim-visible-toolbar) ); - --dim-content-top: calc(var(--dim-header-top) + var(--dim-tabs-panel-height)); --dim-large-form-margin: 20px; } diff --git a/packages/web/src/Screen.svelte b/packages/web/src/Screen.svelte index 5ba23f30f..497412c64 100644 --- a/packages/web/src/Screen.svelte +++ b/packages/web/src/Screen.svelte @@ -13,8 +13,8 @@ visibleTitleBar, visibleToolbar, } from './stores'; - import TabsPanel from './widgets/TabsPanel.svelte'; - import TabRegister from './TabRegister.svelte'; + import TabsPanel from './tabpanel/TabsPanel.svelte'; + import TabRegister from './tabpanel/TabRegister.svelte'; import CommandPalette from './commands/CommandPalette.svelte'; import Toolbar from './widgets/Toolbar.svelte'; import splitterDrag from './utility/splitterDrag'; @@ -27,6 +27,8 @@ import TitleBar from './widgets/TitleBar.svelte'; import FontIcon from './icons/FontIcon.svelte'; import getElectron from './utility/getElectron'; + import TabsContainer from './tabpanel/TabsContainer.svelte'; + import MultiTabsContainer from './tabpanel/MultiTabsContainer.svelte'; $: currentThemeType = $currentThemeDefinition?.themeType == 'dark' ? 'theme-type-dark' : 'theme-type-light'; @@ -69,11 +71,8 @@ {/if} -
- -
-
- +
+
{#if $selectedWidget && $visibleWidgetSideBar}
diff --git a/packages/web/src/appobj/ConnectionAppObject.svelte b/packages/web/src/appobj/ConnectionAppObject.svelte index 5c6c94dfb..100211744 100644 --- a/packages/web/src/appobj/ConnectionAppObject.svelte +++ b/packages/web/src/appobj/ConnectionAppObject.svelte @@ -103,7 +103,7 @@ import { getLocalStorage } from '../utility/storageCache'; import { apiCall, removeVolatileMapping } from '../utility/api'; import ImportDatabaseDumpModal from '../modals/ImportDatabaseDumpModal.svelte'; - import { closeMultipleTabs } from '../widgets/TabsPanel.svelte'; + import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte'; import AboutModal from '../modals/AboutModal.svelte'; import { tick } from 'svelte'; diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index d1baed29a..978d8a5db 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -371,7 +371,7 @@ import ImportDatabaseDumpModal from '../modals/ImportDatabaseDumpModal.svelte'; import ExportDatabaseDumpModal from '../modals/ExportDatabaseDumpModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte'; - import { closeMultipleTabs } from '../widgets/TabsPanel.svelte'; + import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte'; export let data; export let passProps; diff --git a/packages/web/src/buttons/ToolStripButton.svelte b/packages/web/src/buttons/ToolStripButton.svelte index 1623ccf37..bc52c596f 100644 --- a/packages/web/src/buttons/ToolStripButton.svelte +++ b/packages/web/src/buttons/ToolStripButton.svelte @@ -31,6 +31,7 @@ align-self: stretch; display: flex; user-select: none; + margin: 2px 0px; } .button.disabled { color: var(--theme-font-3); diff --git a/packages/web/src/buttons/ToolStripContainer.svelte b/packages/web/src/buttons/ToolStripContainer.svelte index 1ba966899..56e72bb6f 100644 --- a/packages/web/src/buttons/ToolStripContainer.svelte +++ b/packages/web/src/buttons/ToolStripContainer.svelte @@ -1,29 +1,29 @@ -
- -
+
+
+ +
-
- +
+ +
diff --git a/packages/web/src/buttons/ToolStripSplitButton.svelte b/packages/web/src/buttons/ToolStripSplitButton.svelte index c3cd29888..007ca44cd 100644 --- a/packages/web/src/buttons/ToolStripSplitButton.svelte +++ b/packages/web/src/buttons/ToolStripSplitButton.svelte @@ -39,6 +39,7 @@ align-self: stretch; display: flex; user-select: none; + margin: 2px 0px; } .button.disabled { color: var(--theme-font-3); diff --git a/packages/web/src/elements/HorizontalSplitter.svelte b/packages/web/src/elements/HorizontalSplitter.svelte index e2c9ec2f5..d6dfac72b 100644 --- a/packages/web/src/elements/HorizontalSplitter.svelte +++ b/packages/web/src/elements/HorizontalSplitter.svelte @@ -1,5 +1,8 @@
@@ -52,7 +56,10 @@ class="horizontal-split-handle" style={collapsed1 || collapsed2 ? 'display:none' : ''} use:splitterDrag={'clientX'} - on:resizeSplitter={e => (size += e.detail)} + on:resizeSplitter={e => { + size += e.detail; + if (clientWidth > 0) customRatio = size / clientWidth; + }} /> {/if}
@@ -38,7 +39,10 @@ class={'vertical-split-handle'} style={collapsed1 || collapsed2 ? 'display:none' : ''} use:splitterDrag={'clientY'} - on:resizeSplitter={e => (size += e.detail)} + on:resizeSplitter={e => { + size += e.detail; + if (clientHeight > 0) customRatio = size / clientHeight; + }} />
(defaultValue: T, storageName) { @@ -28,6 +30,27 @@ export function writableWithStorage(defaultValue: T, storageName) { return res; } +export function writableWithForage(defaultValue: T, storageName) { + const res = writable(defaultValue); + res.subscribe(value => { + localforage.setItem(storageName, value); + }); + localforage.getItem(storageName).then(value => { + if (value == null) { + const migrated = localStorage.getItem(storageName); + if (migrated) { + localStorage.removeItem(storageName); + const parsed = safeJsonParse(migrated, defaultValue, true); + localforage.setItem(storageName, parsed); + res.set(parsed as T); + } + } else { + res.set(value as T); + } + }); + return res; +} + export function writableSettingsValue(defaultValue: T, storageName) { const res = derived(useSettings(), $settings => { const obj = $settings || {}; @@ -62,7 +85,7 @@ export const openedConnections = writable([]); export const openedSingleDatabaseConnections = writable([]); export const expandedConnections = writable([]); export const currentDatabase = writable(null); -export const openedTabs = writableWithStorage([], 'openedTabs'); +export const openedTabs = writableWithForage([], 'openedTabs'); export const copyRowsFormat = writableWithStorage('textWithoutHeaders', 'copyRowsFormat'); export const extensions = writable(null); export const visibleCommandPalette = writable(null); @@ -92,6 +115,11 @@ export const commandsCustomized = derived([commands, commandsSettings], ([$comma })) ); +export const draggingTab = writable(null); +export const draggingTabTarget = writable(null); +export const draggingDbGroup = writable(null); +export const draggingDbGroupTarget = writable(null); + // export const visibleToolbar = writableWithStorage(true, 'visibleToolbar'); export const visibleToolbar = writable(false); export const leftPanelWidth = writableWithStorage(300, 'leftPanelWidth'); diff --git a/packages/web/src/tabpanel/MultiTabsContainer.svelte b/packages/web/src/tabpanel/MultiTabsContainer.svelte new file mode 100644 index 000000000..5e0f47ede --- /dev/null +++ b/packages/web/src/tabpanel/MultiTabsContainer.svelte @@ -0,0 +1,19 @@ + + + +
+ +
+
+ +
+
diff --git a/packages/web/src/TabContent.svelte b/packages/web/src/tabpanel/TabContent.svelte similarity index 100% rename from packages/web/src/TabContent.svelte rename to packages/web/src/tabpanel/TabContent.svelte diff --git a/packages/web/src/TabRegister.svelte b/packages/web/src/tabpanel/TabRegister.svelte similarity index 57% rename from packages/web/src/TabRegister.svelte rename to packages/web/src/tabpanel/TabRegister.svelte index 3f3f3966d..4027e3bb3 100644 --- a/packages/web/src/TabRegister.svelte +++ b/packages/web/src/tabpanel/TabRegister.svelte @@ -1,11 +1,13 @@ + +
+ +
+
+ +
+ + diff --git a/packages/web/src/widgets/TabsPanel.svelte b/packages/web/src/tabpanel/TabsPanel.svelte similarity index 81% rename from packages/web/src/widgets/TabsPanel.svelte rename to packages/web/src/tabpanel/TabsPanel.svelte index 8c54dec3e..b3e8537c2 100644 --- a/packages/web/src/widgets/TabsPanel.svelte +++ b/packages/web/src/tabpanel/TabsPanel.svelte @@ -43,6 +43,7 @@ const newFiles = files.map(x => ({ ...x, closedTime: shouldShowTab(x) && closeCondition(x, active) ? new Date().getTime() : x.closedTime, + selected: false, })); if (newFiles.find(x => x.selected && shouldShowTab(x))) { @@ -72,6 +73,7 @@ : files.map(x => ({ ...x, closedTime: shouldShowTab(x) && closeCondition(x) ? new Date().getTime() : x.closedTime, + selected: false, })); if (newFiles.find(x => x.selected && shouldShowTab(x))) { @@ -87,8 +89,26 @@ }); }; + function splitTab(multiTabIndex) { + openedTabs.update(tabs => + tabs.map(x => ({ + ...x, + multiTabIndex: x.selected ? 1 - multiTabIndex : x.multiTabIndex, + })) + ); + } + + function splitTabGroup(tabGroupTabs, multiTabIndex) { + openedTabs.update(tabs => + tabs.map(x => ({ + ...x, + multiTabIndex: tabGroupTabs.find(y => x.tabid == y.tabid) ? 1 - multiTabIndex : x.multiTabIndex, + })) + ); + } + const closeTab = closeTabFunc((x, active) => x.tabid == active.tabid); - const closeAll = async () => { + const closeAll = async multiTabIndex => { const closeCandidates = getOpenedTabs() .filter(x => x.unsaved) .filter(x => shouldShowTab(x)); @@ -99,8 +119,12 @@ openedTabs.update(tabs => tabs.map(tab => ({ ...tab, - closedTime: shouldShowTab(tab) ? closedTime : tab.closedTime, + closedTime: + shouldShowTab(tab) && (multiTabIndex == null || multiTabIndex == (tab.multiTabIndex || 0)) + ? closedTime + : tab.closedTime, selected: false, + visibleSecondary: false, })) ); }; @@ -129,7 +153,8 @@ _.get(x, 'props.conid') != _.get(active, 'props.conid') || _.get(x, 'props.database') != _.get(active, 'props.database') ); - const closeOthers = closeTabFunc((x, active) => x.tabid != active.tabid); + const closeOthersInMultiTab = multiTabIndex => + closeTabFunc((x, active) => x.tabid != active.tabid && (x.multiTabIndex || 0) == multiTabIndex); function getTabDbName(tab, connectionList) { if (tab.tabComponent == 'ConnectionTab') return 'Connections'; @@ -252,6 +277,10 @@ getCurrentDatabase, lockedDatabaseMode, getLockedDatabaseMode, + draggingDbGroup, + draggingDbGroupTarget, + draggingTab, + draggingTabTarget, } from '../stores'; import tabs from '../tabs'; import { setSelectedTab } from '../utility/common'; @@ -264,7 +293,11 @@ import TabCloseButton from '../elements/TabCloseButton.svelte'; import CloseTabModal from '../modals/CloseTabModal.svelte'; - $: showTabFilterFunc = tab => shouldShowTab(tab, $lockedDatabaseMode, $currentDatabase); + export let multiTabIndex; + export let shownTab; + + $: showTabFilterFunc = tab => + shouldShowTab(tab, $lockedDatabaseMode, $currentDatabase) && (tab.multiTabIndex || 0) == multiTabIndex; $: connectionList = useConnectionList(); $: currentDbKey = @@ -287,10 +320,9 @@ $: scrollInViewTab($activeTabId); - let draggingTab = null; - let draggingTabTarget = null; - let draggingDbGroup = null; - let draggingDbGroupTarget = null; + $: filteredTabsFromAllParts = $openedTabs.filter(x => shouldShowTab(x, $lockedDatabaseMode, $currentDatabase)); + $: allowSplitTab = + _.uniq(filteredTabsFromAllParts.map(x => x.multiTabIndex || 0)).length == 1 && filteredTabsFromAllParts.length >= 2; const connectionColorFactory = useConnectionColorFactory(3, null, true); @@ -320,11 +352,11 @@ }, { text: 'Close all', - onClick: closeAll, + onClick: () => closeAll(multiTabIndex), }, { text: 'Close others', - onClick: () => closeOthers(tabid), + onClick: () => closeOthersInMultiTab(multiTabIndex)(tabid), }, { text: 'Duplicate', @@ -390,7 +422,7 @@ } } - function dragDropTabs(draggingTabs, targetTabs) { + function dragDropTabs(draggingTabs, targetTabs, multiTabIndex) { if (draggingTabs.find(x => targetTabs.find(y => x.tabid == y.tabid))) return; const items = sortTabs($openedTabs.filter(x => x.closedTime == null)); @@ -422,11 +454,17 @@ return { ...x, tabOrder: index + 1, + multiTabIndex: draggingTabs.find(y => y.tabid == x.tabid) ? multiTabIndex : x.multiTabIndex, }; } return x; }) ); + + draggingDbGroup.set(null); + draggingDbGroupTarget.set(null); + draggingTab.set(null); + draggingTabTarget.set(null); } let domTabs; @@ -440,14 +478,14 @@
-
+
{#each groupedTabs as tabGroup}
{#if !$lockedDatabaseMode}
{ if (e.button == 1) { @@ -459,23 +497,23 @@ use:contextMenu={getDatabaseContextMenu(tabGroup.tabs)} style={$connectionColorFactory( tabGroup.tabs[0].props, - (draggingDbGroup ? tabGroup.grpid == draggingDbGroupTarget?.grpid : tabGroup.tabDbKey == currentDbKey) + ($draggingDbGroup ? tabGroup.grpid == $draggingDbGroupTarget?.grpid : tabGroup.tabDbKey == currentDbKey) ? 2 : 3 )} draggable={true} on:dragstart={e => { - draggingDbGroup = tabGroup; + $draggingDbGroup = tabGroup; }} on:dragenter={e => { - draggingDbGroupTarget = tabGroup; + $draggingDbGroupTarget = tabGroup; }} on:drop={e => { - dragDropTabs(draggingDbGroup.tabs, tabGroup.tabs); + dragDropTabs($draggingDbGroup.tabs, tabGroup.tabs, multiTabIndex); }} on:dragend={e => { - draggingDbGroup = null; - draggingDbGroupTarget = null; + $draggingDbGroup = null; + $draggingDbGroupTarget = null; }} >
@@ -485,11 +523,21 @@ {/if}
-
closeMultipleTabs(tab => tabGroup.tabs.find(x => x.tabid == tab.tabid))} - > - +
+ {#if allowSplitTab && groupedTabs.length > 1} +
splitTabGroup(tabGroup.tabs, multiTabIndex)} + > + +
+ {/if} +
closeMultipleTabs(tab => tabGroup.tabs.find(x => x.tabid == tab.tabid))} + > + +
{/if} @@ -498,32 +546,34 @@
handleTabClick(e, tab.tabid)} on:mouseup={e => handleMouseUp(e, tab.tabid)} use:contextMenu={getContextMenu(tab)} draggable={true} on:dragstart={async e => { - draggingTab = tab; + $draggingTab = tab; await tick(); setSelectedTab(tab.tabid); // console.log('START', tab.tabid); // e.dataTransfer.setData('tab_drag_data', tab.tabid); }} on:dragenter={e => { - draggingTabTarget = tab; + $draggingTabTarget = tab; }} on:drop={e => { - if (draggingTab) { - dragDropTabs([draggingTab], [tab]); + if ($draggingTab) { + dragDropTabs([$draggingTab], [tab], multiTabIndex); } - if (draggingDbGroup) { - dragDropTabs(draggingDbGroup.tabs, [tab]); + if ($draggingDbGroup) { + dragDropTabs($draggingDbGroup.tabs, [tab], multiTabIndex); } }} on:dragend={e => { - draggingTab = null; - draggingTabTarget = null; + $draggingTab = null; + $draggingTabTarget = null; }} > @@ -540,7 +590,16 @@
{/each}
-
newQuery({})} title="New query">
+
+ {#if allowSplitTab} +
splitTab(multiTabIndex)} title="Split window"> + +
+ {/if} +
newQuery({ multiTabIndex })} title="New query"> + +
+
diff --git a/packages/web/src/tabs/ConnectionTab.svelte b/packages/web/src/tabs/ConnectionTab.svelte index 8473f17ad..deff1d03c 100644 --- a/packages/web/src/tabs/ConnectionTab.svelte +++ b/packages/web/src/tabs/ConnectionTab.svelte @@ -31,7 +31,6 @@ import getConnectionLabel from '../utility/getConnectionLabel'; import { onMount } from 'svelte'; import { disconnectServerConnection, openConnection } from '../appobj/ConnectionAppObject.svelte'; - import { closeMultipleTabs } from '../widgets/TabsPanel.svelte'; import { disconnectDatabaseConnection } from '../appobj/DatabaseAppObject.svelte'; export let connection; diff --git a/packages/web/src/tabs/TableDataTab.svelte b/packages/web/src/tabs/TableDataTab.svelte index 83e0ae912..b6150b723 100644 --- a/packages/web/src/tabs/TableDataTab.svelte +++ b/packages/web/src/tabs/TableDataTab.svelte @@ -101,6 +101,7 @@ import { getBoolSettingsValue, getIntSettingsValue } from '../settings/settingsTools'; import useEditorData from '../query/useEditorData'; import { markTabSaved, markTabUnsaved } from '../utility/common'; + import ToolStripButton from '../buttons/ToolStripButton.svelte'; export let tabid; export let conid; @@ -281,32 +282,28 @@ + + { + openNewTab({ + title: pureName, + icon: 'img table-structure', + tabComponent: 'TableStructureTab', + props: { + schemaName, + pureName, + conid, + database, + objectTypeField: 'tables', + }, + }); + }}>Open structure + + collapsedLeftColumnStore.update(x => !x)}>View columns - - { - openNewTab({ - title: pureName, - icon: 'img table-structure', - tabComponent: 'TableStructureTab', - props: { - schemaName, - pureName, - conid, - database, - objectTypeField: 'tables', - }, - }); - }} -/> - - collapsedLeftColumnStore.update(x => !x)} -/> diff --git a/packages/web/src/tabs/TableStructureTab.svelte b/packages/web/src/tabs/TableStructureTab.svelte index 5dbe2db2b..a2237d0fc 100644 --- a/packages/web/src/tabs/TableStructureTab.svelte +++ b/packages/web/src/tabs/TableStructureTab.svelte @@ -60,6 +60,7 @@ import { apiCall } from '../utility/api'; import ToolStripContainer from '../buttons/ToolStripContainer.svelte'; import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte'; + import ToolStripButton from '../buttons/ToolStripButton.svelte'; export let tabid; export let conid; @@ -190,27 +191,25 @@ + + {#if objectTypeField == 'tables'} + { + openNewTab({ + title: pureName, + icon: 'img table', + tabComponent: 'TableDataTab', + props: { + schemaName, + pureName, + conid, + database, + objectTypeField: 'tables', + }, + }); + }}>Open data + {/if} - -{#if objectTypeField == 'tables'} - { - openNewTab({ - title: pureName, - icon: 'img table', - tabComponent: 'TableDataTab', - props: { - schemaName, - pureName, - conid, - database, - objectTypeField: 'tables', - }, - }); - }} - /> -{/if} diff --git a/packages/web/src/utility/ErrorHandler.svelte b/packages/web/src/utility/ErrorHandler.svelte index f71949ee0..18e65cf0e 100644 --- a/packages/web/src/utility/ErrorHandler.svelte +++ b/packages/web/src/utility/ErrorHandler.svelte @@ -1,8 +1,8 @@ diff --git a/packages/web/src/widgets/WidgetColumnBarItem.svelte b/packages/web/src/widgets/WidgetColumnBarItem.svelte index 55861682a..47c6828c8 100644 --- a/packages/web/src/widgets/WidgetColumnBarItem.svelte +++ b/packages/web/src/widgets/WidgetColumnBarItem.svelte @@ -22,6 +22,7 @@ const dynamicProps = writable({ splitterVisible: false, + visibleItemsCount: 0, }); const pushWidgetItemDefinition = getContext('pushWidgetItemDefinition') as any; @@ -62,10 +63,12 @@ storageName && getLocalStorage(storageName) && getLocalStorage(storageName).visible != null ? getLocalStorage(storageName).visible : !collapsed; + + $: collapsible = $dynamicProps.visibleItemsCount != 1 || !visible; {#if !skip && show} - (visible = !visible)}>{title} + (visible = !visible) : null}>{title} {#if visible}
diff --git a/packages/web/src/widgets/WidgetTitle.svelte b/packages/web/src/widgets/WidgetTitle.svelte index dbc127d33..fe57f1e66 100644 --- a/packages/web/src/widgets/WidgetTitle.svelte +++ b/packages/web/src/widgets/WidgetTitle.svelte @@ -1,4 +1,8 @@ -
+ + +
@@ -10,7 +14,7 @@ background-color: var(--theme-bg-1); border: 2px solid var(--theme-border); } - div:hover { + div.clickable:hover { background-color: var(--theme-bg-2); } diff --git a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js index fb536c5f9..9d23c8a7d 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js @@ -199,19 +199,23 @@ class Analyser extends DatabaseAnalyser { x.schema_name == table.schema_name && !uniqueNames.rows.find(y => y.constraint_name == x.index_name) ) - .map(idx => ({ - constraintName: idx.index_name, - isUnique: idx.is_unique, - columns: _.compact( - idx.indkey - .split(' ') - .map(colid => indexcols.rows.find(col => col.oid == idx.oid && col.attnum == colid)) - .filter(col => col != null) - .map(col => ({ - columnName: col.column_name, - })) - ), - })), + .map(idx => { + const indOptionSplit = idx.indoption.split(' '); + return { + constraintName: idx.index_name, + isUnique: idx.is_unique, + columns: _.compact( + idx.indkey + .split(' ') + .map(colid => indexcols.rows.find(col => col.oid == idx.oid && col.attnum == colid)) + .filter(col => col != null) + .map((col, colIndex) => ({ + columnName: col.column_name, + isDescending: parseInt(indOptionSplit[colIndex]) > 0, + })) + ), + }; + }), uniques: indexes.rows .filter( x => diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/indexes.js b/plugins/dbgate-plugin-postgres/src/backend/sql/indexes.js index 06922b159..8cb8de247 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/sql/indexes.js +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/indexes.js @@ -6,6 +6,7 @@ module.exports = ` ix.indisprimary as "is_primary", ix.indisunique as "is_unique", ix.indkey as "indkey", + ix.indoption as "indoption", t.oid as "oid" from pg_class t,