Browser fixes [stage] [arm]

This commit is contained in:
crschnick committed 2025-08-22 16:38:06 +00:00
1 parent dd290ed7f3
commit a3b9eaa9f7
13 files changed
+151 -62

No files matched your search

@@ -172,7 +172,7 @@ public final class McpTools {
throw new BeaconClientException("Directory " + path + " does not exist");
}
try (var stream = recursive ? fs.listFilesRecursively(fs, path) : fs.listFiles(fs, path)) {
try (var stream = recursive ? fs.listFilesRecursively(fs, path).stream() : fs.listFiles(fs, path)) {
var list = stream.toList();
var builder = McpSchema.CallToolResult.builder();
for (FileEntry e : list) {
@@ -202,7 +202,7 @@ public final class McpTools {
}
var regex = Pattern.compile(DataStorageQuery.toRegex(pattern));
try (var stream = recursive ? fs.listFilesRecursively(fs, path) : fs.listFiles(fs, path)) {
try (var stream = recursive ? fs.listFilesRecursively(fs, path).stream() : fs.listFiles(fs, path)) {
var list = stream.toList();
var builder = McpSchema.CallToolResult.builder();
list.stream()
@@ -273,6 +273,14 @@ public final class BrowserFileListComp extends SimpleComp {
return;
}
if (event.isControlDown() || event.isShiftDown() || event.isAltDown() || event.isMetaDown()) {
return;
}
if (typedSelection.get().isEmpty() && typed.equals(" ")) {
return;
}
var updated = typedSelection.get() + typed;
var found = fileList.getShown().getValue().stream()
.filter(browserEntry -> browserEntry.getFileName().toLowerCase().startsWith(updated.toLowerCase()))
@@ -608,9 +616,14 @@ public final class BrowserFileListComp extends SimpleComp {
updateHandler.accept(null, null);
fileList.getShown().addListener((observable, oldValue, newValue) -> {
// Delay to prevent internal tableview exceptions when sorting
Platform.runLater(() -> {
var isSortChange = oldValue.size() == newValue.size() && new HashSet<>(oldValue).containsAll(newValue);
if (isSortChange) {
Platform.runLater(() -> {
updateHandler.accept(oldValue, newValue);
});
} else {
updateHandler.accept(oldValue, newValue);
});
}
});
fileList.getFileSystemModel().getCurrentPath().addListener((observable, oldValue, newValue) -> {
if (oldValue == null) {
@@ -114,16 +114,16 @@ class BrowserFileListNameCell extends TableCell<BrowserEntry, String> {
return;
}
var selection = typedSelection.get() + " ";
var found = fileList.getShown().getValue().stream()
.filter(browserEntry ->
browserEntry.getFileName().toLowerCase().startsWith(selection))
.findFirst();
// Ugly fix to prevent space from showing the menu when there is a file matching
// Due to the table view input map, these events always get sent and consumed, not allowing us to
// differentiate between these cases
if (found.isPresent()) {
return;
if (!typedSelection.get().isEmpty()) {
var selection = typedSelection.get() + " ";
var found = fileList.getShown().getValue().stream().filter(
browserEntry -> browserEntry.getFileName().toLowerCase().startsWith(selection)).findFirst();
// Ugly fix to prevent space from showing the menu when there is a file matching
// Due to the table view input map, these events always get sent and consumed, not allowing us to
// differentiate between these cases
if (found.isPresent()) {
return;
}
}
var selected = fileList.getSelection();
@@ -9,11 +9,15 @@ import io.xpipe.app.comp.augment.ContextMenuAugment;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.util.GlobalTimer;
import io.xpipe.app.util.InputHelper;
import io.xpipe.app.util.PlatformThread;
import io.xpipe.core.FilePath;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.MenuButton;
@@ -30,6 +34,7 @@ import javafx.scene.layout.VBox;
import atlantafx.base.controls.Spacer;
import org.kordamp.ikonli.javafx.FontIcon;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -220,13 +225,22 @@ public class BrowserFileSystemTabComp extends SimpleComp {
});
});
// Delay show to hide file list changes happening
// Not perfect, but covers most of the cases of small directories
var showOverview = new SimpleBooleanProperty(true);
model.getCurrentPath().subscribe(path -> {
GlobalTimer.delay(() -> {
showOverview.setValue(path == null);
}, Duration.ofMillis(250));
});
var home = new BrowserOverviewComp(model).styleClass("browser-overview");
var stack = new MultiContentComp(
Map.of(
home,
model.getCurrentPath().isNull(),
showOverview,
fileList,
model.getCurrentPath().isNull().not()),
showOverview.not()),
false);
var r = stack.styleClass("browser-content-container").createRegion();
r.focusedProperty().addListener((observable, oldValue, newValue) -> {
@@ -30,6 +30,7 @@ import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.SelectionMode;
import lombok.Getter;
import lombok.NonNull;
@@ -37,10 +38,7 @@ import java.io.IOException;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -84,6 +82,11 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
return;
}
if (n.getTransferred() == 0) {
progress.setValue(n);
return;
}
var changedHistory = false;
if (progress.getValue() != null) {
var last = progressesIntervalHistory.isEmpty()
@@ -229,8 +232,23 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
return;
}
var all = new ArrayList<FileEntry>();
all.addAll(entries);
for (BrowserEntry browserEntry : fileList.getAll().getValue()) {
var fe = browserEntry.getRawFileEntry();
if (fe.getKind() == FileKind.LINK && entries.stream().anyMatch(o -> o.getPath().equals(fe.resolved().getPath()))) {
all.add(fe);
}
}
for (FileEntry fileEntry : entries) {
if (fileEntry.getKind() == FileKind.LINK) {
all.add(fileEntry.resolved());
}
}
try {
for (var e : entries) {
for (var e : all) {
var refresh = fileSystem.getFileInfo(e.getPath());
fileList.updateEntry(e.getPath(), refresh.orElse(null));
}
@@ -316,6 +334,11 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
return Optional.empty();
}
if (path == null) {
currentPath.set(null);
return Optional.empty();
}
try {
// Start shell in case we exited
startIfNeeded();
@@ -324,11 +347,6 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
return Optional.ofNullable(cps);
}
if (path == null) {
currentPath.set(null);
return Optional.empty();
}
// Fix common issues with paths
var adjustedPath = BrowserFileSystemHelper.adjustPath(this, path);
if (!Objects.equals(path, adjustedPath)) {
@@ -18,6 +18,7 @@ import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -304,24 +305,45 @@ public class BrowserFileTransferOperation {
flatFiles.put(source, directoryName);
var baseRelative = source.getPath().getParent().toDirectory();
try (var stream = source.getFileSystem().listFilesRecursively(source.getFileSystem(), source.getPath())) {
List<FileEntry> list = stream.toList();
for (FileEntry fileEntry : list) {
if (cancelled()) {
return;
}
var list = new ArrayList<FileEntry>();
source.getFileSystem().traverseFilesRecursively(source.getFileSystem(), source.getPath(), fileEntry -> {
if (cancelled()) {
progress.accept(BrowserTransferProgress.finished(source.getName() + " ...", totalSize.get()));
return false;
}
var rel = fileEntry
.getPath()
.relativize(baseRelative)
.toUnix()
.toString();
flatFiles.put(fileEntry, rel);
if (fileEntry.getKind() == FileKind.FILE) {
// This one is up-to-date and does not need to be recalculated
// If we don't have a size, it doesn't matter that much as the total size is only for display
totalSize.addAndGet(fileEntry.getFileSizeLong().orElse(0));
}
var rel = fileEntry
.getPath()
.relativize(baseRelative)
.toUnix()
.toString();
flatFiles.put(fileEntry, rel);
if (fileEntry.getKind() == FileKind.FILE) {
// This one is up-to-date and does not need to be recalculated
// If we don't have a size, it doesn't matter that much as the total size is only for display
totalSize.addAndGet(fileEntry.getFileSizeLong().orElse(0));
progress.accept(new BrowserTransferProgress(source.getName() + " ...", 0, totalSize.get()));
}
list.add(fileEntry);
return true;
});
for (FileEntry fileEntry : list) {
if (cancelled()) {
return;
}
var rel = fileEntry
.getPath()
.relativize(baseRelative)
.toUnix()
.toString();
flatFiles.put(fileEntry, rel);
if (fileEntry.getKind() == FileKind.FILE) {
// This one is up-to-date and does not need to be recalculated
// If we don't have a size, it doesn't matter that much as the total size is only for display
totalSize.addAndGet(fileEntry.getFileSizeLong().orElse(0));
progress.accept(new BrowserTransferProgress(source.getName(), 0, totalSize.get()));
}
}
} else {
@@ -45,7 +45,7 @@ public class BrowserStatusBarComp extends SimpleComp {
bar.apply(struc -> {
struc.get().widthProperty().subscribe(value -> {
var veryConstrained = value.doubleValue() < 600;
var somewhatConstrained = value.doubleValue() < 750;
var somewhatConstrained = value.doubleValue() < 710;
struc.get().getChildren().get(2).setVisible(!somewhatConstrained);
struc.get().getChildren().get(2).setManaged(!somewhatConstrained);
struc.get().getChildren().get(4).setVisible(!veryConstrained);
@@ -7,8 +7,11 @@ import io.xpipe.core.FilePath;
import java.io.Closeable;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
public interface FileSystem extends Closeable, AutoCloseable {
@@ -49,18 +52,29 @@ public interface FileSystem extends Closeable, AutoCloseable {
Stream<FileEntry> listFiles(FileSystem system, FilePath file) throws Exception;
default Stream<FileEntry> listFilesRecursively(FileSystem system, FilePath file) throws Exception {
return listFiles(system, file).flatMap(fileEntry -> {
if (fileEntry.getKind() != FileKind.DIRECTORY) {
return Stream.of(fileEntry);
default List<FileEntry> listFilesRecursively(FileSystem system, FilePath file) throws Exception {
var all = new ArrayList<FileEntry>();
traverseFilesRecursively(system, file, all::add);
return all;
}
default void traverseFilesRecursively(FileSystem system, FilePath file, Predicate<FileEntry> visitor) throws Exception {
List<FileEntry> base;
try (var filesStream = listFiles(system, file)) {
base = filesStream.toList();
}
for (FileEntry fileEntry : base) {
if (!visitor.test(fileEntry)) {
return;
}
try {
return Stream.concat(Stream.of(fileEntry), listFilesRecursively(system, fileEntry.getPath()));
} catch (Exception e) {
throw new RuntimeException(e);
if (fileEntry.getKind() != FileKind.DIRECTORY) {
continue;
}
});
traverseFilesRecursively(system, fileEntry.getPath(), visitor);
}
}
List<FilePath> listRoots() throws Exception;
@@ -40,6 +40,7 @@ public enum DocumentationLink {
VNC("guide/vnc"),
REAL_VNC("guide/vnc#realvnc-server"),
SSH("guide/ssh"),
SSH_GATEWAYS("guide/ssh#gateways-and-jump-servers"),
SSH_HOST_KEYS("troubleshoot/ssh#no-matching-host-key-type-found"),
SSH_KEX("troubleshoot/ssh#no-matching-key-exchange-method"),
SSH_IPV6("troubleshoot/ssh#ipv6-issues"),
@@ -101,7 +101,7 @@ public class ShellTemp {
"-Force"))
.executeAndCheck();
} else {
sc.command(CommandBuilder.of().add("rm", "-f").add("\"" + prefix.toString() + "\"*"))
sc.command(CommandBuilder.of().add("rm", "-f").add("\"" + prefix.toString() + "\"*").add("2>/dev/null"))
.executeAndCheck();
}
}
+13 -6
View File
@@ -51,6 +51,19 @@ The fonts on macOS have been updated with the goal of better readability. If you
- Add support to launch VsCode Insiders and Trae as well in the VsCode SSH launch menu
- The custom SSH agent setting now works differently. To use the agent socket specified in the settings menu, you will now have to select the custom SSH agent for a connection. The default OpenSSH agent will no longer use this option
## File browser
- Files with trailing or leading spaces are now included in the file list
- The initial transfer size calculation for large directories is now dynamically updated and shown
- Fix execute action on Windows not being limited to certain file types
- Fix refresh of single files failing on Windows systems
- Fix execute action not showing confirmation dialog if enabled
- Fix not supporting dollar signs in directory names
- Fix conflict dialog being cut off
- Fix file listing not working on Solaris systems
- Fix renames not working in cmd
- Fix script arguments not being passed with file selection
## Other
- Tailscale connections are now a top-level entry and can be synced via git
@@ -72,13 +85,7 @@ The fonts on macOS have been updated with the goal of better readability. If you
- Fix small parts of the UI moving a bit on hover
- Fix Bitwarden integration in some cases requiring the master password every time
- Fix restart button not working on Linux
- Fix file browser execute action on Windows not being limited to certain file types
- Fix file browser refresh of single files failing on Windows systems
- Fix file browser execute action not showing confirmation dialog if enabled
- Fix file browser not supporting dollar signs in directory names
- Fix file browser conflict dialog being cut off
- Fix license check becoming invalid if xpipe was left running for more than a week
- Fix application freeze when having password manager identities while password manager was not running
- Fix git vaultversion conflict not being solved automatically
- Fix file listing in file browser not working on Solaris systems
- Fix BSD and Solaris systems not being recognized correctly
@@ -60,7 +60,7 @@ public class SimpleScriptStore extends ScriptStore implements SelfReferentialSto
shellControl.getShellDialect().getNewLine().getNewLineString()));
var targetType = shellControl.getOriginalShellDialect();
var script = ScriptHelper.createExecScript(targetType, shellControl, fixedCommands);
return targetType.sourceScriptCommand(shellControl, script.toString());
return targetType.sourceScriptCommand(shellControl, script.toString()) + " " + targetType.getCatchAllVariable();
}
return null;
+1 -1
View File
@@ -1 +1 @@
18.0-32
18.0-33