Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
b77db21
feat(linux-editor): name the tab's database and schema in the editor bar
sedax90 Oct 30, 2026
f5c2d42
docs(linux-editor): add the changelog entry
sedax90 Oct 30, 2026
48a216d
feat(linux-editor): switch a query tab to another MySQL or MariaDB da…
sedax90 Oct 30, 2026
7dd1bc7
docs(linux-editor): add the changelog entry
sedax90 Oct 30, 2026
35be6ed
feat(linux-editor): switch a query tab's database on SQL Server, Clic…
sedax90 Oct 30, 2026
c47fc28
docs(linux-editor): add the changelog entry
sedax90 Oct 30, 2026
d4cc649
fix(linux-editor): refuse a MongoDB database name a use statement can…
sedax90 Oct 30, 2026
d2549cb
feat(linux-editor): move a PostgreSQL query tab to another database b…
sedax90 Oct 30, 2026
b56bb37
docs(linux-editor): add the changelog entry
sedax90 Oct 30, 2026
03ba56d
feat(linux-session): open a connection's session in another of the se…
sedax90 Oct 30, 2026
0f86941
docs(linux): propose a session per open database of a connection
sedax90 Oct 30, 2026
84dfe86
Merge remote-tracking branch 'origin/main' into feat/linux-editor-dat…
datlechin Oct 30, 2026
fb4e698
wip: saved-in key
sedax90 Oct 30, 2026
30e2e27
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
sedax90 Oct 30, 2026
9f6c1d7
feat(linux-workspace): open another of a connection's databases besid…
sedax90 Oct 30, 2026
e08f518
docs(linux-workspace): add the changelog entry
sedax90 Oct 30, 2026
0def6aa
feat(linux-editor): take a query tab moved to another database to tha…
sedax90 Oct 30, 2026
2c528e7
docs(linux-editor): add the changelog entry
sedax90 Oct 30, 2026
0c8f034
fix(linux-editor): name the database a tab's session is in, and only …
datlechin Oct 30, 2026
e9448f1
feat(linux-workspace): name a tab's database in its title when not th…
sedax90 Oct 30, 2026
d4787ae
docs(linux-workspace): add the changelog entry
sedax90 Oct 30, 2026
5bc735b
Merge branch 'feat/linux-editor-database-picker' into feat/linux-edit…
datlechin Oct 30, 2026
a771366
fix(linux-editor): move a tab's own session with the driver, and comp…
datlechin Oct 30, 2026
c86f693
fix(linux-editor): tell the workspace when a USE moves the tab
datlechin Oct 30, 2026
f1ff043
Merge branch 'feat/linux-editor-database-switch' into feat/linux-edit…
datlechin Oct 30, 2026
0c0e7c2
fix(linux-editor): move SQL Server, ClickHouse, Cassandra and MongoDB…
datlechin Oct 30, 2026
b51d85e
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
2bb98f9
fix(linux-editor): open a PostgreSQL tab's session in its database th…
datlechin Oct 30, 2026
ef2d68c
fix(linux-session): open a sibling session at the connection's Safe M…
datlechin Oct 30, 2026
a283924
docs(linux): record the design the database switch is built on
datlechin Oct 30, 2026
b2dc979
docs(linux): name the ADR's decision in the index
datlechin Oct 30, 2026
642c553
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
d9cbcd6
Merge branch 'feat/linux-session-per-database' into feat/linux-worksp…
datlechin Oct 30, 2026
22d04f0
Merge branch 'docs/linux-adr-database-sessions' into feat/linux-works…
datlechin Oct 30, 2026
2be40fd
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
57d7d9a
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
b59e7c6
fix(linux-workspace): close a database that opened after its connecti…
datlechin Oct 30, 2026
2f8f1de
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
ab6ffeb
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
cbe0a11
fix(linux-editor): end a session whose database after a USE the serve…
datlechin Oct 30, 2026
3738fe2
fix(linux-editor): end a run only once the tab knows the database it …
datlechin Oct 30, 2026
abad14b
Merge branch 'feat/linux-editor-database-picker' into feat/linux-edit…
datlechin Oct 30, 2026
755a489
fix(linux-editor): report only the keyspace Cassandra confirmed, and …
datlechin Oct 30, 2026
d85b302
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
91baad7
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
a24efc1
Merge branch 'feat/linux-editor-database-switch' into feat/linux-edit…
datlechin Oct 30, 2026
08dbf68
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
185a5cb
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
a250df6
fix(linux-workspace): close a connection's databases with it under on…
datlechin Oct 30, 2026
f9fafd2
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
2d368b5
fix(linux-editor): hand a database's session to every tab waiting for…
datlechin Oct 30, 2026
0da67c1
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
b35a1b0
test(linux-session): count the session's own hold on its credentials
datlechin Oct 30, 2026
db94834
Merge branch 'feat/linux-session-per-database' into feat/linux-worksp…
datlechin Oct 30, 2026
d577b46
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
41f6c1d
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
cb30659
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
ad372fe
test(linux-mssql): pin the bracket quoting a move's USE uses
datlechin Oct 30, 2026
8cad125
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
74646c7
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
2687fca
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
93ababb
fix(linux-editor): offer the databases of a connection opened without…
datlechin Oct 30, 2026
615302c
test(linux-editor): a connection without a database name names the se…
datlechin Oct 30, 2026
1e57089
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
b77db8f
Merge branch 'feat/linux-editor-database-switch' into feat/linux-edit…
datlechin Oct 30, 2026
d7ef12e
fix(linux-editor): keep a PostgreSQL tab's session until one opens in…
datlechin Oct 30, 2026
67d362e
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
52a8d0f
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
ce84720
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
42efe7d
fix(linux-editor): refresh a moved tab's database after its DDL, keep…
datlechin Oct 30, 2026
3d592b9
fix(linux-workspace): keep another database's table state apart, and …
datlechin Oct 30, 2026
5af7be9
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
bfe0592
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
139e75f
test(linux-clickhouse): read the collected rows without a binding
datlechin Oct 30, 2026
a124560
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
0f333fb
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
95dcff7
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
42162ee
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
2b50233
fix(linux-editor): show a database name's underscores in the menu
datlechin Oct 30, 2026
de81995
Merge branch 'feat/linux-editor-database-switch' into feat/linux-edit…
datlechin Oct 30, 2026
8c79b3c
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
a8c10e9
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
40fb44d
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
3159291
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
cfd96f7
refactor(linux-editor): reuse the menu label helper for database names
datlechin Oct 30, 2026
1c53758
Merge branch 'feat/linux-editor-database-switch' into feat/linux-edit…
datlechin Oct 30, 2026
d10a3c8
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
7ca7123
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
90d36e7
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
6d25083
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
eb2be50
test(linux-workspace): ask the tear-down question over a list of work…
datlechin Oct 30, 2026
af3650c
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
5634f9a
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
cde4cfe
test(linux-workspace): an open connection's menu offers Open Database
datlechin Oct 30, 2026
515ba78
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
9cc3de0
refactor(linux-workspace): keep the input handler short by naming the…
datlechin Oct 30, 2026
f22d21f
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
4f70da8
Merge origin/main after #3896 landed
datlechin Oct 30, 2026
c27dad0
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
7fa1d4f
test(linux-workspace): name the file names without a closure
datlechin Oct 30, 2026
a804c9c
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
f223b92
Merge origin/main after #3896 landed
datlechin Oct 30, 2026
0396ea4
Merge origin/main after #3896 landed
datlechin Oct 30, 2026
45a54c4
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
8b911bd
fix(linux-workspace): close a database that joined during its connect…
datlechin Oct 30, 2026
19378be
fix(linux-editor): hand a database's session to its tabs whenever it …
datlechin Oct 30, 2026
6bca56e
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
e50f175
fix(linux-editor): export, describe and complete a moved tab in its o…
datlechin Oct 30, 2026
ff46d66
Merge branch 'feat/linux-editor-database-switch' into feat/linux-edit…
datlechin Oct 30, 2026
5e2dd74
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
495864f
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
a0467a0
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
cc129c2
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
94cea80
test(linux-mssql): create the test's database outside a transaction
datlechin Oct 30, 2026
ff5ef22
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
8a29583
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
c502417
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
6da09ac
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
f942f90
test(linux-editor): a menu for the one database a connection in none …
datlechin Oct 30, 2026
0125ee8
Merge branch 'feat/linux-editor-database-switch' into feat/linux-edit…
datlechin Oct 30, 2026
e07e3b5
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
8f9d571
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
1a77b3c
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
5297938
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
8a67ff5
Merge remote-tracking branch 'origin/main' into feat/linux-editor-dat…
datlechin Oct 30, 2026
0ff2aa8
Merge remote-tracking branch 'origin/main' into feat/linux-editor-dat…
datlechin Oct 30, 2026
e5840c7
Merge remote-tracking branch 'origin/main' into feat/linux-workspace-…
datlechin Oct 30, 2026
f642da3
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
25f8aac
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
75edb70
Merge origin/main after #3897 landed
datlechin Oct 30, 2026
68553f0
Merge branch 'feat/linux-editor-database-switch-more' into feat/linux…
datlechin Oct 30, 2026
ed2f163
Merge branch 'feat/linux-editor-database-switch-reconnect' into feat/…
datlechin Oct 30, 2026
91c4780
Merge branch 'feat/linux-workspace-follows-tab-database' into feat/li…
datlechin Oct 30, 2026
8248750
Merge branch 'feat/linux-editor-follows-database-session' into feat/l…
datlechin Oct 30, 2026
8299b12
Merge main into feat/linux-editor-tab-title-database and keep only th…
datlechin Oct 31, 2026
fde9a3f
fix(linux-editor): retitle a tab whose database the server then names…
datlechin Oct 31, 2026
a34a905
refactor(linux-workspace): handle a tab's database change beside its …
datlechin Oct 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions linux/changelog.d/3904.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A query tab in another of the connection's databases names it in its title, as "Query 1 (analytics)".
13 changes: 10 additions & 3 deletions linux/crates/app/src/ui/editor/tab_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,18 @@ impl SqlEditor {
};
if let Some(editor) = editor.upgrade() {
let imp = editor.imp();
let own = databases.iter().find(|database| database.is_default);
imp.listed_own_database
.replace(own.map(|database| database.name.clone()));
let own = databases
.iter()
.find(|database| database.is_default)
.map(|database| database.name.clone());
let own_changed = imp.listed_own_database.replace(own.clone()) != own;
imp.scope_button.set_menu_model(database_menu(&databases).as_ref());
editor.show_scope();
// A tab already in the database the server now calls the
// connection's own is no longer a moved one.
if own_changed {
editor.emit_by_name::<()>("database-changed", &[]);
}
}
});
}
Expand Down
35 changes: 35 additions & 0 deletions linux/crates/app/src/ui/editor/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2850,6 +2850,41 @@ fn a_connection_in_no_database_offers_one() {
assert_eq!(harness.editor.imp().scope_button_label.label(), "analytics");
}

/// A tab in the database the server names as the connection's own once
/// it lists them again is no longer a moved one, for its title and its
/// record.
#[gtk4::test]
fn a_tab_in_the_database_the_server_then_calls_its_own_is_not_moved() {
let database = |name: &str, is_default: bool| tablepro_core::meta::SchemaInfo {
name: name.to_owned(),
is_default,
is_system: false,
};
let harness = scoped_editor_with(mysql_dialect(), &[], answering(), |script, request| {
if let tablepro_session::connect::RequestTarget::Network { database, .. } = &mut request.target {
*database = None;
}
script
.list_databases
.once(FakeReply::ok(vec![
database("analytics", false),
database("app", false),
]))
.always(FakeReply::ok(vec![database("analytics", false), database("app", true)]));
});
let button = harness.editor.imp().scope_button.get();
wait_until(WAIT, || button.is_visible()).expect("the database menu");
let changed = SignalLog::connect(&harness.editor, "database-changed", |_| ());
pick_database(&harness, "app");
assert_eq!(harness.editor.tab_database().as_deref(), Some("app"));

harness.editor.buffer().set_text("CREATE DATABASE scratch");
run_and_wait(&harness);

wait_until(WAIT, || changed.count() == 2).expect("the workspace to hear the tab is in its own database");
assert_eq!(harness.editor.tab_database(), None);
}

/// All Rows runs the statement again on the connection, in another
/// database than a moved tab's, so only the rows shown are offered.
#[gtk4::test]
Expand Down
17 changes: 13 additions & 4 deletions linux/crates/app/src/ui/workspace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,14 @@ impl WorkspaceTab {
}
}

/// The database an editor tab moved to off the connection's.
pub(crate) fn moved_to(&self) -> Option<String> {
match self {
WorkspaceTab::Editor(slot) => slot.editor.tab_database(),
_ => None,
}
}

/// What the tab's title is made from.
pub(crate) fn identity(&self) -> tab_identity::TabIdentity {
use tab_identity::TabIdentity;
Expand Down Expand Up @@ -500,8 +508,9 @@ pub(crate) enum WorkspaceInput {
/// An editor tab was saved, opened a file, or its text came to
/// differ from its file's or match it again.
EditorTabFileChanged(Uuid),
/// An editor tab moved to another database, which its record keeps.
EditorTabDatabaseChanged,
/// An editor tab moved to another database, which its record keeps
/// and its title names.
EditorTabDatabaseChanged(Uuid),
/// The session's saved tabs and their editor text, read off the GTK
/// thread.
WorkspaceLoaded(workspace_tabs::LoadedWorkspace),
Expand Down Expand Up @@ -1122,7 +1131,7 @@ impl WorkspaceModel {
return;
};
if let Some(tab) = self.workspace_tabs.borrow().get(&id) {
tab_title::apply_tab_title(tab.page(), &title, &self.label);
tab_title::apply_tab_title(tab.page(), &title, &self.label, tab.moved_to().as_deref());
}
if self.index.last_selected() == Some(id) {
self.refresh_title();
Expand Down Expand Up @@ -1266,7 +1275,7 @@ impl WorkspaceModel {
}
WorkspaceInput::EditorTabContentChanged(id) => self.on_editor_tab_content_changed(id),
WorkspaceInput::EditorTabFileChanged(id) => self.on_editor_tab_file_changed(id),
WorkspaceInput::EditorTabDatabaseChanged => self.persist_workspace_state(),
WorkspaceInput::EditorTabDatabaseChanged(id) => self.on_editor_tab_database_changed(id),
WorkspaceInput::WorkspaceLoaded(loaded) => self.on_workspace_loaded(loaded),
WorkspaceInput::ResetWorkspaceLayout => self.on_reset_workspace_layout(),
WorkspaceInput::SafeModeChanged => self.refresh_title(),
Expand Down
3 changes: 2 additions & 1 deletion linux/crates/app/src/ui/workspace/tab_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ impl TabFactory {
&page,
&resolve_tab_title(&slot.identity(), self.parts.naming.get()),
&self.parts.label,
slot.moved_to().as_deref(),
);
self.parts.tabs.borrow_mut().insert(id, slot);
self.parts.input.deliver(WorkspaceInput::WorkspaceTabsChanged);
Expand Down Expand Up @@ -497,7 +498,7 @@ pub(super) fn connect_editor(
let file = input.clone();
editor.connect_file_changed(move |_| file.deliver(WorkspaceInput::EditorTabFileChanged(tab_id)));
let database = input.clone();
editor.connect_database_changed(move |_| database.deliver(WorkspaceInput::EditorTabDatabaseChanged));
editor.connect_database_changed(move |_| database.deliver(WorkspaceInput::EditorTabDatabaseChanged(tab_id)));
let transaction = input.clone();
editor.connect_transaction_changed(move |_, _| transaction.deliver(WorkspaceInput::EditorTransactionChanged));
let toast = input.clone();
Expand Down
63 changes: 49 additions & 14 deletions linux/crates/app/src/ui/workspace/tab_title.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ impl ConnectionLabel {
self.shares_bar.get()
}

/// What a tab names after its title: the connection while the bar is
/// shared, and the tab's database when it moved off the connection's.
fn suffix(&self, moved_to: Option<&str>) -> Option<String> {
let connection = self.shares_bar().then(|| self.name());
suffix(connection, moved_to)
}

/// True when that changed, and the tabs have to be titled again.
pub(crate) fn set_shares_bar(&self, shares: bool) -> bool {
self.shares_bar.replace(shares) != shares
Expand All @@ -67,13 +74,17 @@ impl ConnectionLabel {
/// what the unsaved icon shows, since a screen reader reads a tab's
/// tooltip and not its icon, and it is escaped: AdwTab shows it as Pango
/// markup.
pub(crate) fn apply_tab_title(page: &adw::TabPage, title: &TabTitle, connection: &ConnectionLabel) {
let name = connection.name();
pub(crate) fn apply_tab_title(
page: &adw::TabPage,
title: &TabTitle,
connection: &ConnectionLabel,
moved_to: Option<&str>,
) {
// The overview's search finds a connection's tabs by its name.
page.set_keyword(&name);
let title = match connection.shares_bar() {
true => name_connection(title.clone(), &name),
false => title.clone(),
page.set_keyword(&connection.name());
let title = match connection.suffix(moved_to) {
Some(suffix) => name_place(title.clone(), &suffix),
None => title.clone(),
};
page.set_title(&title.label);
let unsaved = page.icon().is_some().then(|| crate::i18n::gettext("Unsaved changes"));
Expand All @@ -84,16 +95,29 @@ pub(crate) fn apply_tab_title(page: &adw::TabPage, title: &TabTitle, connection:
page.set_tooltip(&glib::markup_escape_text(&lines.join("\n")));
}

/// A tab beside another connection's names its own after its title,
/// which stays the useful part once ellipsized. The tooltip names it on a
/// line of its own, which a cut label loses.
fn name_connection(title: TabTitle, connection: &str) -> TabTitle {
let tooltip = [title.tooltip.as_deref().unwrap_or(&title.label), connection].join("\n");
/// The connection, the database, or both, as "prod, analytics".
fn suffix(connection: Option<String>, database: Option<&str>) -> Option<String> {
match (connection, database) {
// Translators: a connection and one of its databases, after a tab's title.
(Some(connection), Some(database)) => Some(crate::i18n::gettext_f(
"{connection}, {database}",
&[("connection", &connection), ("database", database)],
)),
(connection, database) => connection.or_else(|| database.map(str::to_owned)),
}
}

/// A tab beside another connection's names its own after its title, and
/// a tab in another database names that, since the title stays the
/// useful part once ellipsized. The tooltip names them on a line of its
/// own, which a cut label loses.
fn name_place(title: TabTitle, place: &str) -> TabTitle {
let tooltip = [title.tooltip.as_deref().unwrap_or(&title.label), place].join("\n");
TabTitle {
// Translators: a tab's title and its connection, while several connections share the tab bar.
// Translators: a tab's title and its connection while several connections share the tab bar, or the database it runs in when not the connection's.
label: crate::i18n::gettext_f(
"{title} ({connection})",
&[("title", &title.label), ("connection", connection)],
&[("title", &title.label), ("connection", place)],
),
tooltip: Some(tooltip),
}
Expand Down Expand Up @@ -274,7 +298,7 @@ mod tests {

#[test]
fn a_tab_beside_another_connections_names_its_own_after_its_title() {
let title = name_connection(
let title = name_place(
resolve_tab_title(&TabIdentity::Table(orders()), TableNaming::Bare),
"Shop",
);
Expand All @@ -284,6 +308,17 @@ mod tests {
assert!(!title.label.contains('·'));
}

#[test]
fn a_tab_names_its_database_and_the_connection_it_shares_the_bar_with() {
assert_eq!(suffix(None, Some("analytics")).as_deref(), Some("analytics"));
assert_eq!(
suffix(Some("Shop".to_owned()), Some("analytics")).as_deref(),
Some("Shop, analytics")
);
assert_eq!(suffix(Some("Shop".to_owned()), None).as_deref(), Some("Shop"));
assert_eq!(suffix(None, None), None);
}

#[test]
fn a_script_its_label_shows_whole_has_no_tooltip() {
let title = resolve_tab_title(
Expand Down
19 changes: 19 additions & 0 deletions linux/crates/app/src/ui/workspace/tests/tab_title.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,22 @@ fn a_renamed_connection_retitles_its_tabs_and_the_window() {
assert_eq!(page.keyword().as_deref(), Some("Shop"));
assert_eq!(test.workspace().connection_name(), "Shop");
}

/// A tab moved off the connection's database names the one it runs in.
#[gtk4::test]
fn a_tab_moved_to_another_database_names_it() {
let test = TestWindow::connected_with("MovedTabTitle", |script| {
script.dialect = Arc::new(tablepro_driver_mysql::MySqlDialect::new(
tablepro_driver_mysql::MySqlFlavour::MySql,
&tablepro_core::ServerInfo::new("MySQL", "8.4.0", 8, 4, 0),
));
});
let page = open_editor(&test.workspace());
let editor = editors(&test.window).pop().expect("the editor");

WidgetExt::activate_action(&editor, "editor.database", Some(&"analytics".to_variant())).expect("editor.database");

wait_until(WAIT, || page.title() == "Query 1 (analytics)").expect("the tab to name its database");
let tooltip = page.tooltip().map(|tooltip| tooltip.to_string()).unwrap_or_default();
assert_eq!(tooltip, "Query 1\nanalytics");
}
7 changes: 7 additions & 0 deletions linux/crates/app/src/ui/workspace/workspace_tabs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,13 @@ impl WorkspaceModel {
self.persist_workspace_state();
}

/// A tab that moved to another database is restored there and names
/// it in its title.
pub(super) fn on_editor_tab_database_changed(&self, id: Uuid) {
self.retitle_tab(id);
self.persist_workspace_state();
}

pub(super) fn on_editor_tab_run_state_changed(&self, id: Uuid, running: bool) {
if let Some(WorkspaceTab::Editor(slot)) = self.workspace_tabs.borrow().get(&id) {
slot.page.set_loading(running);
Expand Down
Loading