feat(core,fuse,gui,cli): stop sharing and share dialog polish

StopSharing / StopSharingByUid remove the public link, external
invitations, invitations and members, trying every step and reporting
what is still shared. Shared by Me gets a Stop Sharing… item and
pdfs unshare <path> works without an id.

The Share dialog validates addresses inline, shows spinners on buttons
while requests run, offers a link expiry and shows an existing link's
expiry.
This commit is contained in:
nvrl committed 2026-09-23 04:09:32 +02:00
1 parent dfc48375e2
commit 15985f8684
8 files changed
+497 -37

No files matched your search

+51 -9
View File
@@ -403,14 +403,18 @@ enum Command {
/// New role: viewer, editor or admin.
role: String,
},
/// Remove a member or pending invitation from a node's share.
/// Stop sharing a node, or remove one member or pending invitation.
///
/// With only a path, removes the public link, every invitation and every
/// member. With an id and kind (from `pdfs members`), removes that entry.
Unshare {
/// File/folder path, inside the mountpoint or relative to it.
path: PathBuf,
/// Entry id (membership or invitation id), from `pdfs members`.
id: String,
#[arg(requires = "kind")]
id: Option<String>,
/// Entry kind: member, proton or external.
kind: ShareKindArg,
kind: Option<ShareKindArg>,
},
/// Inspect and restore a file's earlier versions.
Versions {
@@ -1261,12 +1265,17 @@ fn cmd_share_role(path: PathBuf, id: String, kind: ShareKindArg, role: String) -
})?)
}
fn cmd_unshare(path: PathBuf, id: String, kind: ShareKindArg) -> Result<()> {
ok_or_bail(control_request(CtlRequest::RemoveShareEntry {
path: path_arg(&path)?,
id,
kind: kind.to_kind(),
})?)
fn cmd_unshare(path: PathBuf, id: Option<String>, kind: Option<ShareKindArg>) -> Result<()> {
let path = path_arg(&path)?;
let request = match (id, kind) {
(Some(id), Some(kind)) => CtlRequest::RemoveShareEntry {
path,
id,
kind: kind.to_kind(),
},
_ => CtlRequest::StopSharing { path },
};
ok_or_bail(control_request(request)?)
}
fn cmd_public_link(action: PublicLinkCmd) -> Result<()> {
@@ -3353,3 +3362,36 @@ mod login_wait_tests {
assert!(shared_by_line(&entry).unwrap().contains("WARNING"));
}
}
#[cfg(test)]
mod unshare_tests {
use super::*;
use clap::Parser;
#[test]
fn unshare_with_only_a_path_stops_sharing() {
let cli = Cli::try_parse_from(["pdfs", "unshare", "docs/report.pdf"]).unwrap();
assert!(matches!(
cli.command,
Command::Unshare {
id: None,
kind: None,
..
}
));
}
#[test]
fn unshare_with_an_id_needs_its_kind() {
assert!(Cli::try_parse_from(["pdfs", "unshare", "docs", "abc"]).is_err());
let cli = Cli::try_parse_from(["pdfs", "unshare", "docs", "abc", "member"]).unwrap();
assert!(matches!(
cli.command,
Command::Unshare {
id: Some(_),
kind: Some(_),
..
}
));
}
}