changed tabs order algorithm

This commit is contained in:
Jan Prochazka
2021-12-30 16:52:10 +01:00
parent 13c32d4063
commit 10e2d3c632
3 changed files with 141 additions and 101 deletions

View File

@@ -6,7 +6,7 @@ import { GlobalCommand } from './commands/registerCommand';
import { useConfig, useSettings } from './utility/metadataLoaders'; import { useConfig, useSettings } from './utility/metadataLoaders';
import _ from 'lodash'; import _ from 'lodash';
interface TabDefinition { export interface TabDefinition {
title: string; title: string;
closedTime?: number; closedTime?: number;
icon: string; icon: string;
@@ -15,6 +15,7 @@ interface TabDefinition {
busy: boolean; busy: boolean;
tabid: string; tabid: string;
tabComponent: string; tabComponent: string;
tabOrder?: number;
} }
export function writableWithStorage<T>(defaultValue: T, storageName) { export function writableWithStorage<T>(defaultValue: T, storageName) {
@@ -44,7 +45,6 @@ export const activeTab = derived([openedTabs], ([$openedTabs]) => $openedTabs.fi
export const recentDatabases = writableWithStorage([], 'recentDatabases'); export const recentDatabases = writableWithStorage([], 'recentDatabases');
export const pinnedDatabases = writableWithStorage([], 'pinnedDatabases'); export const pinnedDatabases = writableWithStorage([], 'pinnedDatabases');
export const pinnedTables = writableWithStorage([], 'pinnedTables'); export const pinnedTables = writableWithStorage([], 'pinnedTables');
export const tabDatabaseGroupOrder = writableWithStorage({}, 'tabDatabaseGroupOrder');
export const commandsSettings = writable({}); export const commandsSettings = writable({});
export const allResultsInOneTabDefault = writableWithStorage(false, 'allResultsInOneTabDefault'); export const allResultsInOneTabDefault = writableWithStorage(false, 'allResultsInOneTabDefault');
export const archiveFilesAsDataSheets = writableWithStorage([], 'archiveFilesAsDataSheets'); export const archiveFilesAsDataSheets = writableWithStorage([], 'archiveFilesAsDataSheets');

View File

@@ -1,7 +1,7 @@
import _ from 'lodash'; import _ from 'lodash';
import uuidv1 from 'uuid/v1'; import uuidv1 from 'uuid/v1';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { getOpenedTabs, openedTabs, tabDatabaseGroupOrder } from '../stores'; import { getOpenedTabs, openedTabs, TabDefinition } from '../stores';
import tabs from '../tabs'; import tabs from '../tabs';
import { setSelectedTabFunc } from './common'; import { setSelectedTabFunc } from './common';
import localforage from 'localforage'; import localforage from 'localforage';
@@ -73,35 +73,34 @@ export default async function openNewTab(newTab, initialData = undefined, option
} }
} }
openedTabs.update(files => [ openedTabs.update(files => {
...(files || []).map(x => ({ ...x, selected: false })), const dbKey = getTabDbKey(newTab);
const items = sortTabs(files.filter(x => x.closedTime == null));
const newItem = {
...newTab,
tabid,
};
if (dbKey != null) {
const lastIndex = _.findLastIndex(items, x => getTabDbKey(x) == dbKey);
if (lastIndex >= 0) {
items.splice(lastIndex + 1, 0, newItem);
} else {
items.push(newItem);
}
} else {
items.push(newItem);
}
return [
...(files || []).map(x => ({ ...x, selected: false, tabOrder: _.findIndex(items, y => y.tabid == x.tabid) })),
{ {
...newTab, ...newTab,
tabid, tabid,
selected: true, selected: true,
// @ts-ignore tabOrder: _.findIndex(items, y => y.tabid == tabid),
tabOrder: (_.max(files.map(x => x.tabOrder || 0)) || 0) + 1,
}, },
]); ];
const allOpenedTabs = getOpenedTabs();
tabDatabaseGroupOrder.update(groupOrder => {
const groupOrderFiltered = _.pickBy(groupOrder, (v, k) =>
allOpenedTabs.filter(x => x.closedTime == null).find(x => getTabDbKey(x) == k)
);
const dbKey = getTabDbKey({
...newTab,
tabid,
});
const newOrder =
groupOrderFiltered[dbKey] ||
// @ts-ignore
(_.max(Object.values(groupOrderFiltered)) || 0) + 1;
return {
...groupOrderFiltered,
[dbKey]: newOrder,
};
}); });
// console.log('OPENING NEW TAB', newTab); // console.log('OPENING NEW TAB', newTab);
@@ -158,5 +157,29 @@ export function getTabDbKey(tab) {
if (tab.props && tab.props.archiveFolder) { if (tab.props && tab.props.archiveFolder) {
return `archive://${tab.props.archiveFolder}`; return `archive://${tab.props.archiveFolder}`;
} }
return `no://${tab.tabid}`; return null;
}
export function sortTabs(tabs: any[]): any[] {
return _.sortBy(tabs, [x => x.tabOrder || 0, x => getTabDbKey(x), 'title', 'tabid']);
}
export function groupTabs(tabs: any[]) {
const res = [];
for (const tab of sortTabs(tabs)) {
const lastGroup = res[res.length - 1];
if (lastGroup?.tabDbKey == tab.tabDbKey) {
lastGroup.tabs.push(tab);
} else {
res.push({
tabDbKey: tab.tabDbKey,
tabDbName: tab.tabDbName,
tabs: [tab],
grpid: tab.tabid,
});
}
}
return res;
} }

View File

@@ -22,6 +22,26 @@
}); });
}; };
const closeMultipleTabs = closeCondition => {
openedTabs.update(files => {
const newFiles = files.map(x => ({
...x,
closedTime: x.closedTime || (closeCondition(x) ? new Date().getTime() : undefined),
}));
if (newFiles.find(x => x.selected && x.closedTime == null)) {
return newFiles;
}
const selectedIndex = _.findLastIndex(newFiles, x => x.closedTime == null);
return newFiles.map((x, index) => ({
...x,
selected: index == selectedIndex,
}));
});
};
const closeTab = closeTabFunc((x, active) => x.tabid == active.tabid); const closeTab = closeTabFunc((x, active) => x.tabid == active.tabid);
const closeAll = () => { const closeAll = () => {
const closedTime = new Date().getTime(); const closedTime = new Date().getTime();
@@ -60,14 +80,12 @@
} }
function getDbIcon(key) { function getDbIcon(key) {
if (key) {
if (key.startsWith('database://')) return 'icon database'; if (key.startsWith('database://')) return 'icon database';
if (key.startsWith('archive://')) return 'icon archive'; if (key.startsWith('archive://')) return 'icon archive';
if (key.startsWith('server://')) return 'icon server'; if (key.startsWith('server://')) return 'icon server';
return 'icon file';
} }
return 'icon file';
function sortTabs(tabs) {
return _.sortBy(tabs, [x => x['tabOrder'] || 0, 'title', 'tabid']);
} }
registerCommand({ registerCommand({
@@ -124,22 +142,14 @@
import FavoriteModal from '../modals/FavoriteModal.svelte'; import FavoriteModal from '../modals/FavoriteModal.svelte';
import { showModal } from '../modals/modalTools'; import { showModal } from '../modals/modalTools';
import { import { currentDatabase, getActiveTab, getOpenedTabs, openedTabs, activeTabId, getActiveTabId } from '../stores';
currentDatabase,
getActiveTab,
getOpenedTabs,
openedTabs,
activeTabId,
getActiveTabId,
tabDatabaseGroupOrder,
} from '../stores';
import tabs from '../tabs'; import tabs from '../tabs';
import { setSelectedTab } from '../utility/common'; import { setSelectedTab } from '../utility/common';
import contextMenu from '../utility/contextMenu'; import contextMenu from '../utility/contextMenu';
import getConnectionLabel from '../utility/getConnectionLabel'; import getConnectionLabel from '../utility/getConnectionLabel';
import { isElectronAvailable } from '../utility/getElectron'; import { isElectronAvailable } from '../utility/getElectron';
import { getConnectionInfo, useConnectionList } from '../utility/metadataLoaders'; import { getConnectionInfo, useConnectionList } from '../utility/metadataLoaders';
import { duplicateTab, getTabDbKey } from '../utility/openNewTab'; import { duplicateTab, getTabDbKey, sortTabs, groupTabs } from '../utility/openNewTab';
import { useConnectionColorFactory } from '../utility/useConnectionColor'; import { useConnectionColorFactory } from '../utility/useConnectionColor';
$: connectionList = useConnectionList(); $: connectionList = useConnectionList();
@@ -159,15 +169,17 @@
tabDbKey: getTabDbKey(tab), tabDbKey: getTabDbKey(tab),
})); }));
$: tabsByDb = _.groupBy(tabsWithDb, 'tabDbKey'); $: groupedTabs = groupTabs(tabsWithDb);
$: dbKeys = _.sortBy(_.keys(tabsByDb), [x => $tabDatabaseGroupOrder[x] || 0, x => x]);
// $: tabsByDb = _.groupBy(tabsWithDb, 'tabDbKey');
// $: dbKeys = _.sortBy(_.keys(tabsByDb), [x => $tabDatabaseGroupOrder[x] || 0, x => x]);
$: scrollInViewTab($activeTabId); $: scrollInViewTab($activeTabId);
let draggingTab = null; let draggingTab = null;
let draggingTabTarget = null; let draggingTabTarget = null;
let draggingDbKey = null; let draggingDbGroup = null;
let draggingDbKeyTarget = null; let draggingDbGroupTarget = null;
const connectionColorFactory = useConnectionColorFactory(3, null, true); const connectionColorFactory = useConnectionColorFactory(3, null, true);
@@ -260,13 +272,13 @@
function dragDropTab(draggingTab, targetTab) { function dragDropTab(draggingTab, targetTab) {
if (draggingTab.tabid == targetTab.tabid) return; if (draggingTab.tabid == targetTab.tabid) return;
if (getTabDbKey(draggingTab) != getTabDbKey(targetTab)) { // if (getTabDbKey(draggingTab) != getTabDbKey(targetTab)) {
dragDropDbKey(getTabDbKey(draggingTab), getTabDbKey(targetTab)); // // dragDropDbKey(getTabDbKey(draggingTab), getTabDbKey(targetTab));
return; // return;
} // }
const dbKey = getTabDbKey(draggingTab); // const dbKey = getTabDbKey(draggingTab);
const items = sortTabs(tabsByDb[dbKey]); const items = sortTabs($openedTabs.filter(x => x.closedTime == null));
const dstIndex = _.findIndex(items, x => x.tabid == targetTab.tabid); const dstIndex = _.findIndex(items, x => x.tabid == targetTab.tabid);
const srcIndex = _.findIndex(items, x => x.tabid == draggingTab.tabid); const srcIndex = _.findIndex(items, x => x.tabid == draggingTab.tabid);
if (srcIndex < 0 || dstIndex < 0) { if (srcIndex < 0 || dstIndex < 0) {
@@ -296,78 +308,83 @@
); );
} }
function dragDropDbKey(draggingDbKey, targetDbKey) { // function dragDropDbKey(draggingDbKey, targetDbKey) {
if (!draggingDbKey) return; // if (!draggingDbKey) return;
if (targetDbKey == draggingDbKey) return; // if (targetDbKey == draggingDbKey) return;
const groupOrderFiltered = _.pickBy($tabDatabaseGroupOrder, (v, k) => // const groupOrderFiltered = _.pickBy($tabDatabaseGroupOrder, (v, k) =>
$openedTabs.filter(x => x.closedTime == null).find(x => getTabDbKey(x) == k) // $openedTabs.filter(x => x.closedTime == null).find(x => getTabDbKey(x) == k)
); // );
const items = _.sortBy(_.keys(groupOrderFiltered), x => groupOrderFiltered[x]); // const items = _.sortBy(_.keys(groupOrderFiltered), x => groupOrderFiltered[x]);
const dstIndex = _.indexOf(items, targetDbKey); // const dstIndex = _.indexOf(items, targetDbKey);
const srcIndex = _.indexOf(items, draggingDbKey); // const srcIndex = _.indexOf(items, draggingDbKey);
if (srcIndex < 0 || dstIndex < 0) { // if (srcIndex < 0 || dstIndex < 0) {
console.warn('Drag tab group index not found'); // console.warn('Drag tab group index not found');
return; // return;
} // }
const newItems = // const newItems =
dstIndex < srcIndex // dstIndex < srcIndex
? [...items.slice(0, dstIndex), draggingDbKey, ...items.slice(dstIndex).filter(x => x != draggingDbKey)] // ? [...items.slice(0, dstIndex), draggingDbKey, ...items.slice(dstIndex).filter(x => x != draggingDbKey)]
: [ // : [
...items.slice(0, dstIndex + 1).filter(x => x != draggingDbKey), // ...items.slice(0, dstIndex + 1).filter(x => x != draggingDbKey),
draggingDbKey, // draggingDbKey,
...items.slice(dstIndex + 1), // ...items.slice(dstIndex + 1),
]; // ];
const newGroupOrder = {}; // const newGroupOrder = {};
for (const key in groupOrderFiltered) { // for (const key in groupOrderFiltered) {
const index = newItems.indexOf(key); // const index = newItems.indexOf(key);
newGroupOrder[key] = index >= 0 ? index + 1 : groupOrderFiltered[key]; // newGroupOrder[key] = index >= 0 ? index + 1 : groupOrderFiltered[key];
} // }
tabDatabaseGroupOrder.set(newGroupOrder); // tabDatabaseGroupOrder.set(newGroupOrder);
} // }
</script> </script>
{#each dbKeys as dbKey} {#each groupedTabs as tabGroup}
<div class="db-wrapper"> <div class="db-wrapper">
<div <div
class="db-name" class="db-name"
class:selected={draggingDbKey ? dbKey == draggingDbKeyTarget : tabsByDb[dbKey][0].tabDbKey == currentDbKey} class:selected={draggingDbGroup
on:click={() => handleSetDb(tabsByDb[dbKey][0].props)} ? tabGroup.grpid == draggingDbGroupTarget?.grpid
use:contextMenu={getDatabaseContextMenu(tabsByDb[dbKey])} : tabGroup.tabDbKey == currentDbKey}
on:click={() => handleSetDb(tabGroup.tabs[0].props)}
use:contextMenu={getDatabaseContextMenu(tabGroup.tabs)}
style={$connectionColorFactory( style={$connectionColorFactory(
tabsByDb[dbKey][0].props, tabGroup.tabs[0].props,
(draggingDbKey ? dbKey == draggingDbKeyTarget : tabsByDb[dbKey][0].tabDbKey == currentDbKey) ? 2 : 3 (draggingDbGroup ? tabGroup.grpid == draggingDbGroupTarget?.grpid : tabGroup.tabDbKey == currentDbKey) ? 2 : 3
)} )}
draggable={true} draggable={true}
on:dragstart={e => { on:dragstart={e => {
draggingDbKey = dbKey; draggingDbGroup = tabGroup;
}} }}
on:dragenter={e => { on:dragenter={e => {
draggingDbKeyTarget = dbKey; draggingDbGroupTarget = tabGroup;
}} }}
on:drop={e => { on:drop={e => {
dragDropDbKey(draggingDbKey, dbKey); // dragDropDbKey(draggingDbKey, dbKey);
}} }}
on:dragend={e => { on:dragend={e => {
draggingDbKey = null; draggingDbGroup = null;
draggingDbKeyTarget = null; draggingDbGroupTarget = null;
}} }}
> >
<FontIcon icon={getDbIcon(dbKey)} /> <FontIcon icon={getDbIcon(tabGroup.tabDbKey)} />
{tabsByDb[dbKey][0].tabDbName} {tabGroup.tabDbName}
{#if tabsByDb[dbKey].length > 1} {#if tabGroup.tabs.length > 1}
<span class="close-button-right tabCloseButton" on:click={e => closeWithSameDb(tabsByDb[dbKey][0].tabid)}> <span
class="close-button-right tabCloseButton"
on:click={e => closeMultipleTabs(tab => tabGroup.tabs.find(x => x.tabid == tab.tabid))}
>
<FontIcon icon="icon close" /> <FontIcon icon="icon close" />
</span> </span>
{/if} {/if}
</div> </div>
<div class="db-group"> <div class="db-group">
{#each sortTabs(tabsByDb[dbKey]) as tab} {#each tabGroup.tabs as tab}
<div <div
id={`file-tab-item-${tab.tabid}`} id={`file-tab-item-${tab.tabid}`}
class="file-tab-item" class="file-tab-item"