mirror of
				https://github.com/Fabio286/antares.git
				synced 2025-06-05 21:59:22 +02:00 
			
		
		
		
	feat: connections sorted by last usage by default and option to pin them
This commit is contained in:
		| @@ -9,7 +9,7 @@ | ||||
|          /> | ||||
|          <ul class="settingbar-elements"> | ||||
|             <Draggable | ||||
|                v-model="connections" | ||||
|                v-model="pinnedConnectionsArr" | ||||
|                :item-key="'uid'" | ||||
|                @start="isDragging = true" | ||||
|                @end="dragStop" | ||||
| @@ -23,11 +23,26 @@ | ||||
|                      @contextmenu.prevent="contextMenu($event, element)" | ||||
|                      @mouseover.self="tooltipPosition" | ||||
|                   > | ||||
|                      <i class="settingbar-element-icon dbi" :class="`dbi-${element.client} ${getStatusBadge(element.uid)}`" /> | ||||
|                      <i class="settingbar-element-icon dbi" :class="[`dbi-${element.client}`, getStatusBadge(element.uid), (pinnedConnections.has(element.uid) ? 'settingbar-element-pin' : false)]" /> | ||||
|                      <span v-if="!isDragging" class="ex-tooltip-content">{{ getConnectionName(element.uid) }}</span> | ||||
|                   </li> | ||||
|                </template> | ||||
|             </Draggable> | ||||
|  | ||||
|             <div v-if="pinnedConnectionsArr.length" class="divider" /> | ||||
|  | ||||
|             <li | ||||
|                v-for="connection in unpinnedConnectionsArr" | ||||
|                :key="connection.uid" | ||||
|                class="settingbar-element btn btn-link ex-tooltip" | ||||
|                :class="{'selected': connection.uid === selectedWorkspace}" | ||||
|                @click.stop="selectWorkspace(connection.uid)" | ||||
|                @contextmenu.prevent="contextMenu($event, connection)" | ||||
|                @mouseover.self="tooltipPosition" | ||||
|             > | ||||
|                <i class="settingbar-element-icon dbi" :class="[`dbi-${connection.client}`, getStatusBadge(connection.uid)]" /> | ||||
|                <span v-if="!isDragging" class="ex-tooltip-content">{{ getConnectionName(connection.uid) }}</span> | ||||
|             </li> | ||||
|             <li | ||||
|                class="settingbar-element btn btn-link ex-tooltip" | ||||
|                :class="{'selected': 'NEW' === selectedWorkspace}" | ||||
| @@ -56,7 +71,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { ref, Ref, computed } from 'vue'; | ||||
| import { ref, Ref, computed, watch } from 'vue'; | ||||
| import { storeToRefs } from 'pinia'; | ||||
| import { useApplicationStore } from '@/stores/application'; | ||||
| import { useConnectionsStore } from '@/stores/connections'; | ||||
| @@ -74,7 +89,7 @@ const { connections: storedConnections, pinnedConnections, lastConnections } = s | ||||
| const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore); | ||||
|  | ||||
| const { showSettingModal, showScratchpad } = applicationStore; | ||||
| const { getConnectionName, updateConnections } = connectionsStore; | ||||
| const { getConnectionName, updatePinnedConnections } = connectionsStore; | ||||
| const { getWorkspace, selectWorkspace } = workspacesStore; | ||||
|  | ||||
| const isLinux = process.platform === 'linux'; | ||||
| @@ -83,17 +98,31 @@ const isDragging: Ref<boolean> = ref(false); | ||||
| const contextEvent: Ref<MouseEvent> = ref(null); | ||||
| const contextConnection: Ref<ConnectionParams> = ref(null); | ||||
|  | ||||
| const connections = computed({ | ||||
|    get () { | ||||
|       return storedConnections.value; | ||||
|    }, | ||||
|    set (value: ConnectionParams[]) { | ||||
|       updateConnections(value); | ||||
| const pinnedConnectionsArr = computed({ | ||||
|    get: () => [...pinnedConnections.value].map(c => storedConnections.value.find(sc => sc.uid === c)).filter(Boolean), | ||||
|    set: (value: ConnectionParams[]) => { | ||||
|       const pinnedUid = value.reduce((acc, curr) => { | ||||
|          acc.push(curr.uid); | ||||
|          return acc; | ||||
|       }, []); | ||||
|  | ||||
|       updatePinnedConnections(pinnedUid); | ||||
|    } | ||||
| }); | ||||
|  | ||||
| const pinnedConnectionsArr = computed(() => storedConnections.value.filter(c => pinnedConnections.value.has(c.uid))); | ||||
| const unpinnedConnectionsArr = computed(() => storedConnections.value.filter(c => !pinnedConnections.value.has(c.uid))); | ||||
| const unpinnedConnectionsArr = computed(() => { | ||||
|    return storedConnections.value | ||||
|       .filter(c => !pinnedConnections.value.has(c.uid)) | ||||
|       .map(c => { | ||||
|          const connTime = lastConnections.value.find((lc) => lc.uid === c.uid)?.time || 0; | ||||
|          return { ...c, time: connTime }; | ||||
|       }) | ||||
|       .sort((a, b) => { | ||||
|          if (a.time < b.time) return 1; | ||||
|          else if (a.time > b.time) return -1; | ||||
|          return 0; | ||||
|       }); | ||||
| }); | ||||
|  | ||||
| const hasUpdates = computed(() => ['available', 'downloading', 'downloaded', 'link'].includes(updateStatus.value)); | ||||
|  | ||||
| @@ -129,13 +158,33 @@ const getStatusBadge = (uid: string) => { | ||||
| }; | ||||
|  | ||||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||
| const dragStop = (e: any) => { // TODO: temp | ||||
| const dragStop = (e: any) => { | ||||
|    isDragging.value = false; | ||||
|  | ||||
|    setTimeout(() => { | ||||
|       tooltipPosition(e.originalEvent.target.parentNode); | ||||
|    }, 200); | ||||
| }; | ||||
|  | ||||
| watch(unpinnedConnectionsArr, (newVal, oldVal) => { | ||||
|    if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) { | ||||
|       setTimeout(() => { | ||||
|          const element = document.querySelector<HTMLElement>('.settingbar-element.selected'); | ||||
|          if (element) { | ||||
|             const rect = element.getBoundingClientRect(); | ||||
|             const elemTop = rect.top; | ||||
|             const elemBottom = rect.bottom; | ||||
|             const isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight); | ||||
|  | ||||
|             if (!isVisible) { | ||||
|                element.setAttribute('tabindex', '-1'); | ||||
|                element.focus(); | ||||
|                element.removeAttribute('tabindex'); | ||||
|             } | ||||
|          } | ||||
|       }, 50); | ||||
|    } | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| @@ -217,6 +266,20 @@ const dragStop = (e: any) => { // TODO: temp | ||||
|             bottom: initial; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .settingbar-element-pin{ | ||||
|           margin: 0 auto; | ||||
|  | ||||
|           &::before { | ||||
|             font: normal normal normal 14px/1 "Material Design Icons"; | ||||
|             content: "\F0403"; | ||||
|             transform: rotate(45deg); | ||||
|             opacity: .25; | ||||
|             bottom: -8px; | ||||
|             left: -4px; | ||||
|             position: absolute; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -125,9 +125,9 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue'; | ||||
| import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Prop, Ref, ref, watch } from 'vue'; | ||||
| import { Ace } from 'ace-builds'; | ||||
| import { EventInfos } from 'common/interfaces/antares'; | ||||
| import { ConnectionParams, EventInfos } from 'common/interfaces/antares'; | ||||
| import { useI18n } from 'vue-i18n'; | ||||
| import { useNotificationsStore } from '@/stores/notifications'; | ||||
| import { useWorkspacesStore } from '@/stores/workspaces'; | ||||
| @@ -141,7 +141,7 @@ const { t } = useI18n(); | ||||
|  | ||||
| const props = defineProps({ | ||||
|    tabUid: String, | ||||
|    connection: Object, | ||||
|    connection: Object as Prop<ConnectionParams>, | ||||
|    tab: Object, | ||||
|    isSelected: Boolean, | ||||
|    schema: String | ||||
| @@ -281,7 +281,7 @@ originalScheduler.value = { | ||||
|    state: 'DISABLE' | ||||
| }; | ||||
|  | ||||
| originalScheduler.value = JSON.parse(JSON.stringify(originalScheduler.value)); | ||||
| localScheduler.value = { ...originalScheduler.value }; | ||||
|  | ||||
| setTimeout(() => { | ||||
|    resizeQueryEditor(); | ||||
|   | ||||
| @@ -60,12 +60,15 @@ const useFocusTrap = (args?: {disableAutofocus?: boolean}) => { | ||||
|       focusableElements = (trapRef.value as HTMLElement).querySelectorAll( | ||||
|          focusableElementsSelector | ||||
|       ); | ||||
|  | ||||
|       if (focusableElements.length) { | ||||
|          $firstFocusable = focusableElements[0]; | ||||
|          $lastFocusable = focusableElements[focusableElements.length - 1]; | ||||
|          document.addEventListener('keydown', keyHandler); | ||||
|          isInitiated.value = true; | ||||
|          if (!localArgs.disableAutofocus) $firstFocusable.focus(); | ||||
|       } | ||||
|    } | ||||
|  | ||||
|    function clearFocusTrap () { | ||||
|       document.removeEventListener('keydown', keyHandler); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|   width: 42px; | ||||
|   height: 42px; | ||||
|   background-size: cover; | ||||
|   position: relative; | ||||
|  | ||||
|   &.dbi-mysql { | ||||
|     background-image: url("../images/svg/mysql.svg"); | ||||
|   | ||||
| @@ -368,6 +368,10 @@ option:checked { | ||||
|   } | ||||
| } | ||||
|  | ||||
| .divider { | ||||
|   margin: 0.15rem 0.3rem; | ||||
| } | ||||
|  | ||||
| .table-dropdown { | ||||
|   .menu { | ||||
|     min-width: 100%; | ||||
|   | ||||
| @@ -148,6 +148,10 @@ | ||||
|     background: transparent; | ||||
|   } | ||||
|  | ||||
|   .divider { | ||||
|     border-top: 0.05rem solid rgba($body-font-color-dark, 0.1); | ||||
|   } | ||||
|  | ||||
|   .form-switch .form-icon::before { | ||||
|     background: $bg-color-light-dark; | ||||
|   } | ||||
|   | ||||
| @@ -94,6 +94,10 @@ | ||||
|     background: transparent; | ||||
|   } | ||||
|  | ||||
|   .divider { | ||||
|     border-top: 0.05rem solid rgba($body-font-color-dark, 0.1); | ||||
|   } | ||||
|  | ||||
|   .tile { | ||||
|     transition: background 0.2s; | ||||
|  | ||||
|   | ||||
| @@ -19,7 +19,7 @@ export const useConnectionsStore = defineStore('connections', { | ||||
|    state: () => ({ | ||||
|       connections: persistentStore.get('connections', []) as ConnectionParams[], | ||||
|       pinnedConnections: new Set([...persistentStore.get('pinnedConnections', []) as string[]]) as Set<string>, | ||||
|       lastConnections: persistentStore.get('lastConnections', {}) as {[k: string]: number} | ||||
|       lastConnections: persistentStore.get('lastConnections', []) as {uid: string; time: number}[] | ||||
|    }), | ||||
|    getters: { | ||||
|       getConnectionName: state => (uid: string) => { | ||||
| @@ -52,6 +52,8 @@ export const useConnectionsStore = defineStore('connections', { | ||||
|       deleteConnection (connection: ConnectionParams) { | ||||
|          this.connections = (this.connections as ConnectionParams[]).filter(el => el.uid !== connection.uid); | ||||
|          persistentStore.set('connections', this.connections); | ||||
|          (this.pinnedConnections as Set<string>).delete(connection.uid); | ||||
|          persistentStore.set('pinnedConnections', [...this.pinnedConnections]); | ||||
|       }, | ||||
|       editConnection (connection: ConnectionParams) { | ||||
|          const editedConnections = (this.connections as ConnectionParams[]).map(conn => { | ||||
| @@ -66,6 +68,10 @@ export const useConnectionsStore = defineStore('connections', { | ||||
|          this.connections = connections; | ||||
|          persistentStore.set('connections', this.connections); | ||||
|       }, | ||||
|       updatePinnedConnections (pinned: string[]) { | ||||
|          this.pinnedConnections = new Set(pinned); | ||||
|          persistentStore.set('pinnedConnections', [...this.pinnedConnections]); | ||||
|       }, | ||||
|       pinConnection (uid: string) { | ||||
|          (this.pinnedConnections as Set<string>).add(uid); | ||||
|          persistentStore.set('pinnedConnections', [...this.pinnedConnections]); | ||||
| @@ -75,7 +81,13 @@ export const useConnectionsStore = defineStore('connections', { | ||||
|          persistentStore.set('pinnedConnections', [...this.pinnedConnections]); | ||||
|       }, | ||||
|       updateLastConnection (uid: string) { | ||||
|          this.lastConnections[uid] = new Date().getTime(); | ||||
|          const cIndex = (this.lastConnections as {uid: string; time: number}[]).findIndex((c) => c.uid === uid); | ||||
|  | ||||
|          if (cIndex >= 0) | ||||
|             this.lastConnections[cIndex].time = new Date().getTime(); | ||||
|          else | ||||
|             this.lastConnections.push({ uid, time: new Date().getTime() }); | ||||
|  | ||||
|          persistentStore.set('lastConnections', this.lastConnections); | ||||
|       } | ||||
|    } | ||||
|   | ||||
| @@ -718,44 +718,6 @@ export const useWorkspacesStore = defineStore('workspaces', { | ||||
|          ); | ||||
|          persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs); | ||||
|       }, | ||||
|       // setTabFields ({ cUid, tUid, fields }: { cUid: string; tUid: string; fields: any }) { | ||||
|       //    this.workspaces = (this.workspaces as Workspace[]).map(workspace => { | ||||
|       //       if (workspace.uid === cUid) { | ||||
|       //          return { | ||||
|       //             ...workspace, | ||||
|       //             tabs: workspace.tabs.map(tab => { | ||||
|       //                if (tab.uid === tUid) | ||||
|       //                   return { ...tab, fields }; | ||||
|       //                else | ||||
|       //                   return tab; | ||||
|       //             }) | ||||
|       //          }; | ||||
|       //       } | ||||
|       //       else | ||||
|       //          return workspace; | ||||
|       //    }); | ||||
|  | ||||
|       //    persistentStore.set(cUid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === cUid).tabs); | ||||
|       // }, | ||||
|       // setTabKeyUsage ({ cUid, tUid, keyUsage }: { cUid: string; tUid: string; keyUsage: any }) { | ||||
|       //    this.workspaces = (this.workspaces as Workspace[]).map(workspace => { | ||||
|       //       if (workspace.uid === cUid) { | ||||
|       //          return { | ||||
|       //             ...workspace, | ||||
|       //             tabs: workspace.tabs.map(tab => { | ||||
|       //                if (tab.uid === tUid) | ||||
|       //                   return { ...tab, keyUsage }; | ||||
|       //                else | ||||
|       //                   return tab; | ||||
|       //             }) | ||||
|       //          }; | ||||
|       //       } | ||||
|       //       else | ||||
|       //          return workspace; | ||||
|       //    }); | ||||
|  | ||||
|       //    persistentStore.set(cUid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === cUid).tabs); | ||||
|       // }, | ||||
|       setUnsavedChanges ({ uid, tUid, isChanged }: { uid: string; tUid: string; isChanged: boolean }) { | ||||
|          this.workspaces = (this.workspaces as Workspace[]).map(workspace => { | ||||
|             if (workspace.uid === uid) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user