Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
164 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
e3335e3
feat(linux-session): reopen a connection's other open databases besid…
sedax90 Oct 30, 2026
de7d591
docs(linux-session): add the changelog entry
sedax90 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
f6dc91a
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
datlechin Oct 30, 2026
b59e7c6
fix(linux-workspace): close a database that opened after its connecti…
datlechin Oct 30, 2026
d205786
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
d65ec83
fix(linux-session): say a record with another database beside a conne…
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
3441758
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
fbc0612
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
3b3f54b
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
f5d0927
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
20d6f8c
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
0893074
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
6225eac
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
994676c
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
d2c9c2d
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
ae83662
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
5f5da3b
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
bc7ca38
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
a1abc38
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
910a582
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
dcb4b34
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
734fe2e
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
92843e7
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
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
e449ea4
Merge branch 'feat/linux-editor-tab-title-database' into feat/linux-r…
datlechin Oct 30, 2026
4db3b20
Rebuild on main: reopen a connection's other databases through its owner
datlechin Oct 31, 2026
1e58e35
fix(linux-session): keep a failed connection's other databases for th…
datlechin Oct 31, 2026
d97e8ba
test(linux-session): compare the record with a slice of the key it keeps
datlechin Oct 31, 2026
6cdc0fc
fix(linux-session): restore databases beside a connection started mea…
datlechin Oct 31, 2026
985af4f
fix(linux-session): let any connect of a failed connection reopen the…
datlechin Oct 31, 2026
96c64a7
fix(linux-session): reopen a failed connection's databases when its e…
datlechin Oct 31, 2026
96daddd
fix(linux-session): open a retried connection's databases in the wind…
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/3905.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A database opened beside its connection reopens with it at the next launch, with its tabs.
26 changes: 14 additions & 12 deletions linux/crates/app/src/ui/session_window/connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,19 +619,21 @@ impl SessionWindow {
if !self.tear_down_session(&key) {
return;
}
let Some(saved) = stored else {
self.show_toast(&crate::i18n::gettext("The connection was deleted."));
return;
};
let source = ConnectSource::Saved(Box::new(saved));
let Some(claim) = self.claim_for(&key) else {
return;
};
if let Some(mut pending) = self.spawn_connect(claim, source, None, CredentialDemand::default()) {
pending.databases = databases;
self.imp().connects.borrow_mut().push(pending);
match stored {
Some(saved) => self.connect_saved(saved, databases),
None => self.show_toast(&crate::i18n::gettext("The connection was deleted.")),
}
self.connects_changed();
}

/// Connect `saved` through the window's one connect path, and open
/// `databases` beside it once it joins.
pub(super) fn connect_saved(&self, saved: SavedConnection, databases: Vec<String>) {
self.connect_reopening(
None,
ConnectSource::Saved(Box::new(saved)),
CredentialDemand::default(),
databases,
);
}

/// Tick the level of the session in front in the main menu.
Expand Down
6 changes: 5 additions & 1 deletion linux/crates/app/src/ui/session_window/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ use crate::ui::welcome_view::WelcomeView;
use crate::ui::workspace::WorkspaceShell;
use crate::workspace::{CloseGuards, WindowInhibitor};

/// A connect that failed beside the window's sessions: where it came
/// from, why it failed, and the other databases its next connect opens.
pub(super) type FailureBeside = (ConnectSource, ConnectFailure, Vec<String>);

#[derive(Default, gtk::CompositeTemplate, glib::Properties)]
#[template(resource = "/app/tablepro/TablePro/ui/session-window.ui")]
#[properties(wrapper_type = super::SessionWindow)]
Expand All @@ -53,7 +57,7 @@ pub struct SessionWindow {
pub(super) failed: RefCell<Option<FailedConnect>>,
/// The last failure of each connect that failed beside something
/// else, until the key connects again, for its Details.
pub(super) failures: RefCell<HashMap<SessionKey, (ConnectSource, ConnectFailure)>>,
pub(super) failures: RefCell<HashMap<SessionKey, FailureBeside>>,
/// The shell, from the first session the window adopts to the last
/// one it tears down.
pub(super) shell: RefCell<Option<WorkspaceShell>>,
Expand Down
3 changes: 2 additions & 1 deletion linux/crates/app/src/ui/session_window/locate_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ impl SessionWindow {
if self.failed_saved(located.id).is_none() {
return;
}
if let Some((claim, _, _)) = self.take_failure(&SessionKey::Saved(located.id)) {
if let Some(super::session_page::TakenFailure { claim, .. }) = self.take_failure(&SessionKey::Saved(located.id))
{
self.connect_with(
claim,
ConnectSource::Saved(Box::new(located)),
Expand Down
178 changes: 151 additions & 27 deletions linux/crates/app/src/ui/session_window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ use self::file_location_dialog::FileCheck;
pub(crate) use self::launch_notice::LaunchNotice;
pub(super) use self::picker_page::PickerPage;
use self::resolve_file_identity::{FileResolveError, FileTarget, ResolvedFile, resolve_file_blocking};
use self::session_page::{FailedConnect, OpenSession, PendingConnect, SessionPage, source_key};
use self::session_page::{FailedConnect, OpenSession, PendingConnect, SessionPage, TakenFailure, source_key};
use self::session_window_command::{AttemptError, ConnectFailure, Connected, SessionWindowCommand};
pub(crate) use self::session_window_input::{MovedTab, SessionWindowInput};
use crate::application::{AppServices, WindowHost, WindowLaunch};
Expand Down Expand Up @@ -406,7 +406,7 @@ impl SessionWindow {
self.imp().shell.replace(Some(shell.clone()));
self.sync_tree();
if let Some(tree) = shell.tree() {
for (key, (source, failure)) in self.imp().failures.borrow().iter() {
for (key, (source, failure, _)) in self.imp().failures.borrow().iter() {
tree.set_failure(key, Some((&source_name(source), failure.message.as_str())));
}
}
Expand Down Expand Up @@ -683,7 +683,7 @@ impl SessionWindow {
self.open_database(id, database);
}
}
Err(AttemptError::Failed(failure)) => self.on_connect_failed(claim, source, failure),
Err(AttemptError::Failed(failure)) => self.on_connect_failed(claim, source, failure, databases),
// A location question was asked above, so this is a stop.
Err(AttemptError::Cancelled | AttemptError::AskLocation(_)) => {
let key = claim.key().clone();
Expand All @@ -699,7 +699,15 @@ impl SessionWindow {
/// toast says so and its Details say why. A session restored at
/// launch that no longer opens is not tried again at the next one; a
/// Retry that works records it again.
fn on_connect_failed(&self, claim: SessionClaim, source: ConnectSource, failure: ConnectFailure) {
/// The connection's other databases wait with the failure for the
/// connect that brings it back.
fn on_connect_failed(
&self,
claim: SessionClaim,
source: ConnectSource,
failure: ConnectFailure,
databases: Vec<String>,
) {
tracing::warn!(error = %failure.message, "connect failed");
let imp = self.imp();
let key = claim.key().clone();
Expand All @@ -710,7 +718,12 @@ impl SessionWindow {
ConnectSource::Saved(saved) => failure.missing_file.clone().map(|missing| (saved.id, missing)),
_ => None,
};
self.show_failure(FailedConnect { claim, source, failure });
self.show_failure(FailedConnect {
claim,
source,
failure,
databases,
});
if let Some((id, missing)) = missing {
self.offer_locate(id, missing);
}
Expand All @@ -721,7 +734,9 @@ impl SessionWindow {
if let Some(tree) = self.shell().and_then(|shell| shell.tree()) {
tree.set_failure(&key, Some((&name, failure.message.as_str())));
}
imp.failures.borrow_mut().insert(key.clone(), (source, failure));
imp.failures
.borrow_mut()
.insert(key.clone(), (source, failure, databases));
// The toast goes to the page that shows from here on, which may
// be another connect's progress.
self.connects_changed();
Expand Down Expand Up @@ -892,7 +907,20 @@ impl SessionWindow {
return None;
}
match self.imp().failed.take() {
Some(failed) if failed.claim.key() == key => Some(failed.claim),
Some(FailedConnect {
claim,
source,
failure,
databases,
}) if claim.key() == key => {
// The connect this claim starts takes them, as it takes
// a failure beside the window's sessions.
self.imp()
.failures
.borrow_mut()
.insert(key.clone(), (source, failure, databases));
Some(claim)
}
failed => {
let left = failed.is_some();
drop(failed);
Expand All @@ -915,6 +943,76 @@ impl SessionWindow {

/// Connect with the failed page's claim when there is one, else as
/// any connect does.
/// Connect `source` with `claim`, or a claim of its own, and open
/// `databases` beside it once it joins: a reconnect's or a restore's.
pub(super) fn connect_reopening(
&self,
claim: Option<SessionClaim>,
source: ConnectSource,
demand: CredentialDemand,
databases: Vec<String>,
) {
let key = source_key(&source);
let claim = match claim {
Some(claim) => claim,
None => match self.claim_for(&key) {
Some(claim) => claim,
None => {
self.open_beside(&key, databases);
return;
}
},
};
if let Some(mut pending) = self.spawn_connect(claim, source, None, demand) {
pending.databases.extend(databases);
self.imp().connects.borrow_mut().push(pending);
}
self.connects_changed();
}

/// Open `databases` beside the connection under `key` that is open or
/// connecting already, in this window or the one that holds it.
fn open_beside(&self, key: &SessionKey, databases: Vec<String>) {
let SessionKey::Saved(id) = *key else {
return;
};
if self.holds_session(key) {
for database in databases {
self.open_database(id, database);
}
return;
}
let joined = {
let mut connects = self.imp().connects.borrow_mut();
match connects.iter_mut().find(|pending| pending.claim.key() == key) {
Some(pending) => {
pending.databases.extend(databases.iter().cloned());
true
}
None => false,
}
};
if joined {
return;
}
// Another window holds the connection, and its databases open
// there.
let owner = self
.state()
.and_then(|state| state.context.sessions.window_for(key))
.filter(|owner| *owner != self.id());
let owner = owner.and_then(|owner| {
self.application()?
.windows()
.into_iter()
.filter_map(|window| window.downcast::<SessionWindow>().ok())
.find(|window| window.id() == owner)
});
if let Some(owner) = owner {
owner.open_beside(key, databases);
}
}

fn connect_with(&self, claim: Option<SessionClaim>, source: ConnectSource, demand: CredentialDemand) {
match claim {
Some(claim) => self.start_connect(claim, source, None, demand),
Expand Down Expand Up @@ -991,6 +1089,7 @@ impl SessionWindow {
claim,
source: ConnectSource::File(FileIdentity::new(None, uri)),
failure: ConnectFailure::new(message),
databases: Vec::new(),
});
}
}
Expand Down Expand Up @@ -1047,11 +1146,17 @@ impl SessionWindow {
let id = imp.next_connect.get().wrapping_add(1);
imp.next_connect.set(id);
let key = claim.key();
if imp.failures.borrow_mut().remove(key).is_some()
&& let Some(tree) = self.shell().and_then(|shell| shell.tree())
{
tree.set_failure(key, None);
}
// Whatever brings a failed connection back reopens the other
// databases its failure kept.
let databases = match imp.failures.borrow_mut().remove(key) {
Some((_, _, databases)) => {
if let Some(tree) = self.shell().and_then(|shell| shell.tree()) {
tree.set_failure(key, None);
}
databases
}
None => Vec::new(),
};
let cancel = CancellationToken::new();
let check = self.file_check(&source, answer);
let work = connect_work(state, &source, check, demand, cancel.clone());
Expand All @@ -1062,7 +1167,7 @@ impl SessionWindow {
source,
cancel,
demand,
databases: Vec::new(),
databases,
})
}

Expand Down Expand Up @@ -1186,25 +1291,36 @@ impl SessionWindow {
imp.failures
.borrow()
.get(key)
.map(|(source, failure)| read(source, failure))
.map(|(source, failure, _)| read(source, failure))
}

/// Take the last failure for `key` to act on it, with the failed
/// page's claim when it is the page's.
pub(super) fn take_failure(
&self,
key: &SessionKey,
) -> Option<(Option<SessionClaim>, ConnectSource, ConnectFailure)> {
pub(super) fn take_failure(&self, key: &SessionKey) -> Option<TakenFailure> {
let imp = self.imp();
let page = imp.failed.borrow_mut().take_if(|failed| failed.claim.key() == key);
if let Some(FailedConnect { claim, source, failure }) = page {
return Some((Some(claim), source, failure));
if let Some(FailedConnect {
claim,
source,
databases,
..
}) = page
{
return Some(TakenFailure {
claim: Some(claim),
source,
databases,
});
}
let (source, failure) = imp.failures.borrow_mut().remove(key)?;
let (source, _, databases) = imp.failures.borrow_mut().remove(key)?;
if let Some(tree) = self.shell().and_then(|shell| shell.tree()) {
tree.set_failure(key, None);
}
Some((None, source, failure))
Some(TakenFailure {
claim: None,
source,
databases,
})
}

/// Drop the last failure for `key` beside the window's sessions, and
Expand All @@ -1220,30 +1336,38 @@ impl SessionWindow {
/// Connect again from where the failed connect came from, reading
/// the keyring again.
fn on_retry_connect(&self, key: &SessionKey) {
if let Some((claim, source, _)) = self.take_failure(key) {
self.reconnect(claim, source, CredentialDemand::default());
if let Some(taken) = self.take_failure(key) {
self.reconnect(taken, CredentialDemand::default());
}
}

/// Connect `source` again as it is now: a file is resolved again,
/// since it may have moved, and a saved connection read as saved now,
/// since another window may have edited or deleted it.
fn reconnect(&self, claim: Option<SessionClaim>, source: ConnectSource, demand: CredentialDemand) {
fn reconnect(&self, taken: TakenFailure, demand: CredentialDemand) {
let TakenFailure {
claim,
source,
databases,
} = taken;
match source {
ConnectSource::File(identity) => {
drop(claim);
self.render();
self.on_open_file(gio::File::for_uri(&identity.uri));
}
ConnectSource::Saved(saved) => match self.saved_as_stored(&saved) {
Some(current) => self.connect_with(claim, ConnectSource::Saved(Box::new(current)), demand),
Some(current) => {
self.connect_reopening(claim, ConnectSource::Saved(Box::new(current)), demand, databases)
}
None => {
drop(claim);
self.render();
self.show_toast(&crate::i18n::gettext("The connection was deleted."));
}
},
source => self.connect_with(claim, source, demand),
// An edited connection's retry brings its databases back too.
source => self.connect_reopening(claim, source, demand, databases),
}
}

Expand Down
10 changes: 9 additions & 1 deletion linux/crates/app/src/ui/session_window/other_databases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ impl SessionWindow {
}
(None, Ok(Ok(session))) => drop(session.begin_shutdown()),
(Some(_), Ok(Err(error))) if !matches!(error, ConnectError::Cancelled) => {
// A database restored at launch that no longer opens is
// not tried again at the next one.
self.forget_session(&SessionKey::SavedIn {
id,
database: database.clone(),
});
self.show_toast(&gettext_f(
"Could not open the database “{database}”: {error}",
&[("database", &database), ("error", &connect_error_message(&error))],
Expand All @@ -194,7 +200,8 @@ impl SessionWindow {
return;
};
claim.attach(&session);
let Some(workspace) = self.new_workspace(claim.key().clone(), &session, &shell) else {
let key = claim.key().clone();
let Some(workspace) = self.new_workspace(key.clone(), &session, &shell) else {
drop(session.begin_shutdown());
return;
};
Expand All @@ -216,6 +223,7 @@ impl SessionWindow {
.push(OpenSession::new(claim, session, workspace.clone()));
others
};
self.remember_session(&key, None);
self.render();
shell.add_session(&workspace);
workspace.start();
Expand Down
Loading
Loading