From 7879f70ee504baa3a8f9de9202ca2c5a65195ad7 Mon Sep 17 00:00:00 2001 From: Aitchessbee Date: Wed, 13 Mar 2024 19:02:55 +0530 Subject: [PATCH] added ordering feature for server tabs, fixes #548 --- app/renderer/css/main.css | 4 ++++ app/renderer/js/main.ts | 19 ++++++++++++++++++- app/renderer/js/utils/domain-util.ts | 14 ++++++++++++++ package-lock.json | 14 +++++++++++++- package.json | 4 +++- 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/app/renderer/css/main.css b/app/renderer/css/main.css index 0898191f5..1bcd60f6d 100644 --- a/app/renderer/css/main.css +++ b/app/renderer/css/main.css @@ -145,6 +145,10 @@ body { color: rgb(108 133 146 / 100%); } +.sortable-chosen .server-tooltip { + display: none; +} + .tab { position: relative; margin: 2px 0; diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 7b4abce90..7264c1433 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -28,6 +28,7 @@ import {initializeTray} from "./tray.js"; import {ipcRenderer} from "./typed-ipc-renderer.js"; import * as DomainUtil from "./utils/domain-util.js"; import ReconnectUtil from "./utils/reconnect-util.js"; +import Sortable from "sortablejs"; Sentry.init({}); @@ -57,7 +58,7 @@ const dingSound = new Audio( export class ServerManagerView { $addServerButton: HTMLButtonElement; - $tabsContainer: Element; + $tabsContainer: HTMLElement; $reloadButton: HTMLButtonElement; $loadingIndicator: HTMLButtonElement; $settingsButton: HTMLButtonElement; @@ -81,6 +82,7 @@ export class ServerManagerView { tabIndex: number; presetOrgs: string[]; preferenceView?: PreferenceView; + sortableSidebar: Sortable | null; constructor() { this.$addServerButton = document.querySelector("#add-tab")!; this.$tabsContainer = document.querySelector("#tabs-container")!; @@ -123,6 +125,7 @@ export class ServerManagerView { this.presetOrgs = []; this.functionalTabs = new Map(); this.tabIndex = 0; + this.sortableSidebar = null; } async init(): Promise { @@ -235,6 +238,20 @@ export class ServerManagerView { initSidebar(): void { const showSidebar = ConfigUtil.getConfigItem("showSidebar", true); this.toggleSidebar(showSidebar); + this.sortableSidebar = new Sortable(this.$tabsContainer, { + animation: 150, + onEnd: (event: Sortable.SortableEvent) => { + // Update the domain order in the database + DomainUtil.updateDomainOrder(event.oldIndex || 0, event.newIndex || 0); + + // Update the current active tab index + this.activeTabIndex = event.newIndex || 0; + ConfigUtil.setConfigItem("lastActiveTab", event.newIndex || 0); + + // Reload the app to give the tabs their new indexes + ipcRenderer.send("reload-full-app"); + }, + }); } // Remove the stale UA string from the disk if the app is not freshly diff --git a/app/renderer/js/utils/domain-util.ts b/app/renderer/js/utils/domain-util.ts index 465bb3b55..43b77cbd6 100644 --- a/app/renderer/js/utils/domain-util.ts +++ b/app/renderer/js/utils/domain-util.ts @@ -72,6 +72,20 @@ export function updateDomain(index: number, server: ServerConf): void { db.push(`/domains[${index}]`, server, true); } +export function updateDomainOrder(oldIndex: number, newIndex: number) { + let domains = serverConfSchema + .array() + .parse(db.getObject("/domains")); + + const [movedDomain] = domains.splice(oldIndex, 1); + domains.splice(newIndex, 0, movedDomain); + + // Update each domain in the database with its new order + domains.forEach((domain, index) => { + updateDomain(index, domain); + }); +} + export async function addDomain(server: { url: string; alias: string; diff --git a/package-lock.json b/package-lock.json index 80cd10cd0..fc714eb5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,9 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "gatemaker": "https://github.com/andersk/gatemaker/archive/d31890ae1cb293faabcb1e4e465c673458f6eed2.tar.gz" + "@types/sortablejs": "^1.15.8", + "gatemaker": "https://github.com/andersk/gatemaker/archive/d31890ae1cb293faabcb1e4e465c673458f6eed2.tar.gz", + "sortablejs": "^1.15.2" }, "devDependencies": { "@electron/remote": "^2.0.8", @@ -2207,6 +2209,11 @@ "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, + "node_modules/@types/sortablejs": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.8.tgz", + "integrity": "sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==" + }, "node_modules/@types/verror": { "version": "1.10.9", "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.9.tgz", @@ -9508,6 +9515,11 @@ "npm": ">= 3.0.0" } }, + "node_modules/sortablejs": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", + "integrity": "sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==" + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 6076f3a4c..214150d65 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,9 @@ "InstantMessaging" ], "dependencies": { - "gatemaker": "https://github.com/andersk/gatemaker/archive/d31890ae1cb293faabcb1e4e465c673458f6eed2.tar.gz" + "@types/sortablejs": "^1.15.8", + "gatemaker": "https://github.com/andersk/gatemaker/archive/d31890ae1cb293faabcb1e4e465c673458f6eed2.tar.gz", + "sortablejs": "^1.15.2" }, "devDependencies": { "@electron/remote": "^2.0.8",