Several collections can be open at once, each in its own tab with its own query and results. Closing a tab returns to the one used before.
- A tab is
{ id, context: { connection, database, collection }, type }.idis acrypto.randomUUID().typeis aTabKind; onlyQUERYis ever created. tabsStorekeeps the tabs in aMap, theactiveTabid, andtabHistory, the ids in the order they were last active.addTabcreates a tab.hasContextfinds an open tab of the same type for the same connection id, database and collection. The sidebar uses it so a collection is opened only once.switchTabmoves the id to the end of the history and makes it active.deleteTabremoves the tab and its history entry. If it was active, the last tab in the history becomes active.closeActiveTabdeletes the active tab.Ctrl+Wis bound to it.
TabsContainerdraws the tab strip: the collection name and a close icon per tab, the active one underlined. Below it each tab gets a container that is shown withv-showonly while its tab is active. Inside it aKeepAliveholds the view for the tab kind, keyed by the active tab id.- The view for every kind is
TabViewQuery, see query-tab.md. It reads its context fromtabsStore.getActiveTab(), not from a prop.
- Tabs stay mounted (
573dfc0):v-showandKeepAliveinstead ofv-if, so a tab keeps its query and results. - A history instead of "the tab to the left" (
be509cf): closing a tab goes back to the one used before. - One tab per collection and kind: the sidebar switches to an open tab instead of adding a second one.
| Date | Step | Commit |
|---|---|---|
| 2026-02-17 | Tab store, tab kinds, the sidebar opens tabs | 7717002 |
| 2026-02-17 | Close button | bd72722 |
| 2026-02-17 | Ctrl+W closes the active tab |
748c02a |
| 2026-02-17 | Tab history | be509cf |
| 2026-02-22 | Collection of the active tab highlighted in the sidebar | fdf801a |
| 2026-02-24 | TabViewQuery as the view of a tab |
e0256f3 |
| 2026-02-26 | Tabs stay mounted | 573dfc0 |
Read from the code on 2026-11-03, not reproduced in the running app:
- The views multiply. The view in every tab's container is keyed by the active tab id, not by its own tab. Each container therefore creates an instance for every tab that becomes active, and every new instance runs its query on mount. With n tabs open, opening or revisiting a tab can run up to n queries. The visible container keeps its state, the hidden copies only cost queries.
Ctrl+Enterruns the query in every instance (issue #42), see shortcuts.md.- Closing a tab can run a query and unsubscribe the wrong view. The unmounted views call
CommandRegistry.unsubscribe, whosefindIndex(subscriber)callsexecuteas a predicate, see shortcuts.md. - Tabs outlive their connection. Disconnect and switching connections don't close them, and the view queries the active connection with the tab's database and collection names.
- The tab shows only the collection name. Collections with the same name in two databases look the same.
- Tabs are not saved across restarts.
INDEXES,AGGREGATION,EXPORTER,IMPORTERandSTATISTICSexist as kinds and are all mapped toTabViewQuery. Nothing creates them.
| What | Path |
|---|---|
| Store | src/stores/tabsStore.ts |
| Models | src/domains/tabs/models/, src/domains/context/models/context.ts |
| Strip and containers | src/components/tabs/TabsContainer.vue |
| Opening from the sidebar | handleCollectionSelect in src/components/AppSidebar.vue |