project_panel: Disable undo and redo on read-only projects (#61104)
# Objective Users in a read-only project should have no permission to create, rename, move, trash or delete files, as such, they should also have no way to undo or redo these actions. These changes ensure that the listeners for both `project_panel::Undo` and `project_panel::Redo` are only registered if the project is not read-only. ## Solution The `ProjectPanel` listeners for both the `Undo` and `Redo` actions were not gated behind the existing `!Project::is_read_only` call, on `ProjectPanel::render`, so these changes move the listeners inside that check. ## Testing Currently, there isn't an easy way to manually test this, as these actions were already disabled in collab and the easiest way to get into a read-only project is connect as a collab guest. However, in order to ensure this continues being asserted once we remove the collab restriction, the `project_panel::tests::undo::undo_redo_unavailable_for_read_only_collab_guest` test has been added. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [ ] Unsafe blocks (if any) have justifying comments - [ ] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [ ] Performance impact has been considered and is acceptable --- Release Notes: - N/A
This commit is contained in:
1 parent
7eaddbc5d9
commit
ca2624960f
2 files changed
+46
-7
No files matched your search
@@ -6880,6 +6880,7 @@ impl Render for ProjectPanel {
|
||||
// version that understands these messages.
|
||||
let is_collab = project.is_via_collab();
|
||||
let is_local = project.is_local();
|
||||
let supports_undo = cx.has_flag::<ProjectPanelUndoRedoFeatureFlag>();
|
||||
|
||||
if has_worktree {
|
||||
let item_count = self
|
||||
@@ -7011,13 +7012,6 @@ impl Render for ProjectPanel {
|
||||
.on_action(cx.listener(Self::fold_directory))
|
||||
.on_action(cx.listener(Self::remove_from_project))
|
||||
.on_action(cx.listener(Self::compare_marked_files))
|
||||
.when(
|
||||
!is_collab && cx.has_flag::<ProjectPanelUndoRedoFeatureFlag>(),
|
||||
|el| {
|
||||
el.on_action(cx.listener(Self::undo))
|
||||
.on_action(cx.listener(Self::redo))
|
||||
},
|
||||
)
|
||||
.when(!project.is_read_only(cx), |el| {
|
||||
el.on_action(cx.listener(Self::new_file))
|
||||
.on_action(cx.listener(Self::new_directory))
|
||||
@@ -7031,6 +7025,10 @@ impl Render for ProjectPanel {
|
||||
.on_action(cx.listener(Self::add_to_gitignore))
|
||||
.on_action(cx.listener(Self::add_to_git_info_exclude))
|
||||
.when(!is_collab, |el| el.on_action(cx.listener(Self::trash)))
|
||||
.when(!is_collab && supports_undo, |el| {
|
||||
el.on_action(cx.listener(Self::undo))
|
||||
.on_action(cx.listener(Self::redo))
|
||||
})
|
||||
})
|
||||
.when(
|
||||
project.is_local() || project.is_via_wsl_with_host_interop(cx),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use client::proto;
|
||||
use collections::HashSet;
|
||||
use fs::{FakeFs, Fs};
|
||||
use gpui::{Entity, VisualTestContext};
|
||||
@@ -240,6 +241,12 @@ impl TestContext {
|
||||
.unwrap();
|
||||
let mut cx = VisualTestContext::from_window(window.into(), cx);
|
||||
let panel = workspace.update_in(&mut cx, ProjectPanel::new);
|
||||
|
||||
workspace.update_in(&mut cx, |workspace, window, cx| {
|
||||
workspace.add_panel(panel.clone(), window, cx);
|
||||
workspace.focus_panel::<ProjectPanel>(window, cx);
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
TestContext { panel, fs, cx }
|
||||
@@ -458,3 +465,37 @@ async fn record_via_collab(cx: &mut gpui::TestAppContext) {
|
||||
cx.redo().await;
|
||||
cx.assert_fs_state_is(&["b.txt", "renamed.txt"]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn undo_redo_unavailable_for_read_only_collab_guest(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = TestContext::new(cx).await;
|
||||
let focus_handle = cx
|
||||
.panel
|
||||
.read_with(&cx.cx, |panel, _| panel.focus_handle.clone());
|
||||
|
||||
cx.cx.update(|window, _cx| {
|
||||
assert!(window.is_action_available_in(&crate::Undo, &focus_handle));
|
||||
assert!(window.is_action_available_in(&crate::Redo, &focus_handle));
|
||||
});
|
||||
|
||||
// In order to simulate a read-only project, we mark it both as a collab
|
||||
// session as well as being a guest, which only has read access.
|
||||
// This is currently a bit redundant, seeing as these actions are already
|
||||
// disabled in collab either way. However, we'll want to enable undo/redo in
|
||||
// collab in the future and this test will ensure that, at that point, we
|
||||
// continue to not allow undo/redo in read-only projects.
|
||||
cx.panel.update(&mut cx.cx, |panel, cx| {
|
||||
panel.project.update(cx, |project, cx| {
|
||||
project.mark_as_collab_for_testing();
|
||||
project.set_role(proto::ChannelRole::Guest, cx);
|
||||
});
|
||||
|
||||
assert!(panel.project.read(cx).is_read_only(cx));
|
||||
cx.notify();
|
||||
});
|
||||
|
||||
cx.cx.update(|window, _cx| {
|
||||
assert!(!window.is_action_available_in(&crate::Undo, &focus_handle));
|
||||
assert!(!window.is_action_available_in(&crate::Redo, &focus_handle));
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user