This commit is contained in:
crschnick
2025-06-17 14:42:51 +00:00
parent 01085b37b3
commit cc30ba52a0
28 changed files with 179 additions and 112 deletions
@@ -55,6 +55,7 @@ public class ChgrpActionProvider implements BrowserActionProvider {
.getPath()
.toString())
.toList()));
model.refreshEntriesSync(getEntries());
}
}
}
@@ -54,6 +54,7 @@ public class ChmodActionProvider implements BrowserActionProvider {
.getPath()
.toString())
.toList()));
model.refreshEntriesSync(getEntries());
}
}
}
@@ -55,6 +55,7 @@ public class ChownActionProvider implements BrowserActionProvider {
.getPath()
.toString())
.toList()));
model.refreshSync();
}
}
}
@@ -0,0 +1,41 @@
package io.xpipe.app.browser.action.impl;
import io.xpipe.app.browser.action.BrowserAction;
import io.xpipe.app.browser.action.BrowserActionProvider;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemHelper;
import io.xpipe.core.store.FileKind;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
public class ComputeDirectorySizesActionProvider implements BrowserActionProvider {
@Jacksonized
@SuperBuilder
public static class Action extends BrowserAction {
@Override
public void executeImpl() throws Exception {
var entries = getEntries();
if (entries.size() == 1 && entries.getFirst().getRawFileEntry().equals(model.getCurrentDirectory())) {
entries = model.getFileList().getAll().getValue();
}
for (BrowserEntry be : entries) {
if (be.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY) {
continue;
}
var size = model.getFileSystem().getDirectorySize(be.getRawFileEntry().resolved().getPath());
var fileEntry = be.getRawFileEntry();
fileEntry.resolved().setSize("" + size);
model.getFileList().updateEntry(be.getRawFileEntry().getPath(), fileEntry);
}
}
}
@Override
public String getId() {
return "computeDirectorySizes";
}
}
@@ -29,6 +29,7 @@ import java.time.Instant;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import static io.xpipe.app.util.HumanReadableFormat.byteCount;
import static javafx.scene.control.TableColumn.SortType.ASCENDING;
@@ -493,8 +494,25 @@ public final class BrowserFileListComp extends SimpleComp {
TableColumn<BrowserEntry, String> modeCol,
TableColumn<BrowserEntry, String> ownerCol) {
var lastDir = new SimpleObjectProperty<FileEntry>();
Runnable updateHandler = () -> {
BiConsumer<List<BrowserEntry>, List<BrowserEntry>> updateHandler = (o, n) -> {
PlatformThread.runLaterIfNeeded(() -> {
// Optimization for single entry updates
if (o != null && n != null && o.size() == n.size()) {
var left = new HashSet<>(n);
o.forEach(left::remove);
if (left.size() == 1) {
var updatedEntry = left.iterator().next();
var found = o.stream().filter(browserEntry -> browserEntry.getRawFileEntry().getPath()
.equals(updatedEntry.getRawFileEntry().getPath())).findFirst();
if (found.isPresent()) {
table.refresh();
table.getItems().set(table.getItems().indexOf(found.get()), updatedEntry);
return;
}
}
}
table.setDisable(true);
var newItems = new ArrayList<>(fileList.getShown().getValue());
table.getItems().clear();
@@ -551,17 +569,20 @@ public final class BrowserFileListComp extends SimpleComp {
}
}
lastDir.setValue(currentDirectory);
table.setDisable(false);
});
};
updateHandler.run();
updateHandler.accept(null, null);
fileList.getShown().addListener((observable, oldValue, newValue) -> {
// Delay to prevent internal tableview exceptions when sorting
Platform.runLater(updateHandler);
Platform.runLater(() -> {
updateHandler.accept(oldValue, newValue);
});
});
fileList.getFileSystemModel().getCurrentPath().addListener((observable, oldValue, newValue) -> {
if (oldValue == null) {
updateHandler.run();
updateHandler.accept(null, null);
}
});
}
@@ -7,6 +7,7 @@ import io.xpipe.core.process.OsType;
import io.xpipe.core.store.FileEntry;
import io.xpipe.core.store.FileKind;
import io.xpipe.core.store.FilePath;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
@@ -57,12 +58,13 @@ public final class BrowserFileListModel {
}
}
public void updateEntry(BrowserEntry old, FileEntry n) {
var index = all.getValue().indexOf(old);
if (index == -1) {
public void updateEntry(FilePath p, FileEntry n) {
var found = all.getValue().stream().filter(browserEntry -> browserEntry.getRawFileEntry().getPath().equals(p)).findFirst();
if (found.isEmpty()) {
return;
}
var index = all.getValue().indexOf(found.get());
var l = new ArrayList<>(all.getValue());
if (n != null) {
l.set(index, new BrowserEntry(n, this));
@@ -78,7 +80,7 @@ public final class BrowserFileListModel {
refreshShown();
}
private void refreshShown() {
void refreshShown() {
List<BrowserEntry> filtered = fileSystemModel.getFilter().getValue() != null
? all.getValue().stream()
.filter(entry -> {
@@ -107,7 +109,7 @@ public final class BrowserFileListModel {
return us;
}
public BrowserEntry rename(BrowserEntry old, String newName) {
public BrowserEntry rename(BrowserEntry old, String newName) throws Exception {
if (old == null
|| newName == null
|| fileSystemModel == null
@@ -116,7 +118,6 @@ public final class BrowserFileListModel {
return old;
}
var fullPath = fileSystemModel.getCurrentPath().get().join(old.getFileName());
var newFullPath = fileSystemModel.getCurrentPath().get().join(newName);
// This check will fail on case-insensitive file systems when changing the case of the file
@@ -138,7 +139,7 @@ public final class BrowserFileListModel {
ErrorEventFactory.fromMessage("Target " + newFullPath + " does already exist")
.expected()
.handle();
fileSystemModel.refresh();
fileSystemModel.refreshSync();
return old;
}
}
@@ -144,7 +144,7 @@ class BrowserFileListNameCell extends TableCell<BrowserEntry, String> {
getTableRow().requestFocus();
var it = getTableRow().getItem();
editing.setValue(null);
ThreadHelper.runAsync(() -> {
ThreadHelper.runFailableAsync(() -> {
if (it == null) {
return;
}
@@ -171,13 +171,6 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
});
}
@SneakyThrows
public void refresh() {
BooleanScope.executeExclusive(busy, () -> {
cdSyncWithoutCheck(currentPath.get());
});
}
public void refreshSync() throws Exception {
cdSyncWithoutCheck(currentPath.get());
}
@@ -195,10 +188,8 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
for (BrowserEntry browserEntry : entries) {
var refresh = fileSystem.getFileInfo(browserEntry.getRawFileEntry().getPath());
fileList.updateEntry(browserEntry, refresh.orElse(null));
fileList.updateEntry(browserEntry.getRawFileEntry().getPath(), refresh.orElse(null));
}
cdSyncWithoutCheck(currentPath.get());
}
public FileEntry getCurrentParentDirectory() {
@@ -248,7 +239,7 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
return false;
}
if (AppMainWindow.getInstance().getStage().getWidth() <= 1280) {
if (AppMainWindow.getInstance().getStage().getWidth() <= 1380) {
return false;
}
@@ -1,6 +1,7 @@
package io.xpipe.app.browser.menu.impl;
import io.xpipe.app.browser.action.impl.ChgrpActionProvider;
import io.xpipe.app.browser.action.impl.ChmodActionProvider;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.app.browser.menu.BrowserMenuBranchProvider;
@@ -18,8 +19,6 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
public class ChmodMenuProvider implements BrowserMenuBranchProvider {
@@ -109,24 +108,24 @@ public class ChmodMenuProvider implements BrowserMenuBranchProvider {
private static class FixedProvider implements BrowserMenuLeafProvider {
private final String group;
private final String permissions;
private final boolean recursive;
private FixedProvider(String group, boolean recursive) {
this.group = group;
private FixedProvider(String permissions, boolean recursive) {
this.permissions = permissions;
this.recursive = recursive;
}
@Override
public ObservableValue<String> getName(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return new SimpleStringProperty(group);
return new SimpleStringProperty(permissions);
}
@Override
public void execute(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
var builder = ChgrpActionProvider.Action.builder();
var builder = ChmodActionProvider.Action.builder();
builder.initEntries(model, entries);
builder.group(group);
builder.permissions(permissions);
builder.recursive(recursive);
var action = builder.build();
action.executeAsync();
@@ -162,9 +161,9 @@ public class ChmodMenuProvider implements BrowserMenuBranchProvider {
return;
}
var builder = ChgrpActionProvider.Action.builder();
var builder = ChmodActionProvider.Action.builder();
builder.initEntries(model, entries);
builder.group(permissions.getValue());
builder.permissions(permissions.getValue());
builder.recursive(recursive);
var action = builder.build();
action.executeAsync();
@@ -1,6 +1,7 @@
package io.xpipe.app.browser.menu.impl;
import io.xpipe.app.browser.action.impl.ChgrpActionProvider;
import io.xpipe.app.browser.action.impl.ChownActionProvider;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.app.browser.menu.BrowserMenuBranchProvider;
@@ -18,8 +19,6 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
import java.util.stream.Stream;
@@ -110,24 +109,24 @@ public class ChownMenuProvider implements BrowserMenuBranchProvider {
private static class FixedProvider implements BrowserMenuLeafProvider {
private final String group;
private final String owner;
private final boolean recursive;
private FixedProvider(String group, boolean recursive) {
this.group = group;
private FixedProvider(String owner, boolean recursive) {
this.owner = owner;
this.recursive = recursive;
}
@Override
public ObservableValue<String> getName(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return new SimpleStringProperty(group);
return new SimpleStringProperty(owner);
}
@Override
public void execute(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
var builder = ChgrpActionProvider.Action.builder();
var builder = ChownActionProvider.Action.builder();
builder.initEntries(model, entries);
builder.group(group);
builder.owner(owner);
builder.recursive(recursive);
var action = builder.build();
action.executeAsync();
@@ -163,9 +162,9 @@ public class ChownMenuProvider implements BrowserMenuBranchProvider {
return;
}
var builder = ChgrpActionProvider.Action.builder();
var builder = ChownActionProvider.Action.builder();
builder.initEntries(model, entries);
builder.group(user.getValue());
builder.owner(user.getValue());
builder.recursive(recursive);
var action = builder.build();
action.executeAsync();
@@ -1,5 +1,8 @@
package io.xpipe.app.browser.menu.impl;
import io.xpipe.app.action.AbstractAction;
import io.xpipe.app.browser.action.impl.ComputeDirectorySizesActionProvider;
import io.xpipe.app.browser.action.impl.DeleteActionProvider;
import io.xpipe.app.browser.file.BrowserEntry;
import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
import io.xpipe.app.browser.menu.BrowserMenuCategory;
@@ -10,25 +13,15 @@ import io.xpipe.core.store.FileKind;
import javafx.beans.value.ObservableValue;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
public class ComputeDirectorySizesAction implements BrowserMenuLeafProvider {
public class ComputeDirectorySizesMenuProvider implements BrowserMenuLeafProvider {
@Override
public void execute(BrowserFileSystemTabModel model, List<BrowserEntry> entries) throws Exception {
for (BrowserEntry be : model.getFileList().getAll().getValue()) {
if (be.getRawFileEntry().getKind() != FileKind.DIRECTORY) {
continue;
}
var size =
model.getFileSystem().getDirectorySize(be.getRawFileEntry().getPath());
var fileEntry = be.getRawFileEntry();
fileEntry.setSize("" + size);
model.getFileList().updateEntry(be, fileEntry);
}
public AbstractAction createAction(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
var builder = ComputeDirectorySizesActionProvider.Action.builder();
builder.initEntries(model, entries);
return builder.build();
}
public String getId() {
@@ -42,12 +35,13 @@ public class ComputeDirectorySizesAction implements BrowserMenuLeafProvider {
@Override
public ObservableValue<String> getName(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return AppI18n.observable("computeDirectorySizes");
var topLevel = entries.size() == 1 && entries.getFirst().getRawFileEntry().equals(model.getCurrentDirectory());
return AppI18n.observable(topLevel ? "computeDirectorySizes" : "computeSize");
}
@Override
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return entries.size() == 1 && entries.getFirst().getRawFileEntry().equals(model.getCurrentDirectory());
return entries.stream().allMatch(browserEntry -> browserEntry.getRawFileEntry().getKind() == FileKind.DIRECTORY);
}
@Override
@@ -26,7 +26,7 @@ public class CopyMenuProvider implements BrowserMenuLeafProvider {
@Override
public LabelGraphic getIcon(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return new LabelGraphic.IconGraphic("mdi2c-content-copy");
return new LabelGraphic.IconGraphic("mdoal-file_copy");
}
@Override
@@ -7,6 +7,7 @@ import io.xpipe.app.browser.menu.BrowserMenuCategory;
import io.xpipe.app.browser.menu.BrowserMenuLeafProvider;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.util.ClipboardHelper;
import io.xpipe.app.util.LabelGraphic;
import io.xpipe.core.store.FileKind;
import javafx.beans.property.SimpleObjectProperty;
@@ -35,6 +36,11 @@ public class CopyPathMenuProvider implements BrowserMenuBranchProvider {
return AppI18n.observable("copyLocation");
}
@Override
public LabelGraphic getIcon(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return new LabelGraphic.IconGraphic("mdi2c-content-copy");
}
@Override
public List<BrowserMenuLeafProvider> getBranchingActions(
BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
@@ -34,7 +34,7 @@ public class NewItemMenuProvider implements BrowserMenuBranchProvider {
@Override
public BrowserMenuCategory getCategory() {
return BrowserMenuCategory.MUTATION;
return BrowserMenuCategory.ACTION;
}
@Override
@@ -29,14 +29,11 @@ public interface ShellStore extends DataStore, FileSystemStore, ValidatableStore
}
}
startSessionIfNeeded();
var session = startSessionIfNeeded();
var session = getSession();
// This might be null if this store has been removed from this storage since the session was started
// Then, the cache returns null
if (session == null) {
return standaloneControl().start();
}
// getSession()
return new StubShellControl(session.getShellControl());
}
@@ -38,16 +38,16 @@ public interface SingletonSessionStore<T extends Session>
return (T) getCache("session", getSessionClass(), null);
}
default void startSessionIfNeeded() throws Exception {
default T startSessionIfNeeded() throws Exception {
synchronized (this) {
var s = getSession();
if (s != null) {
if (s.isRunning()) {
return;
return s;
}
s.start();
return;
return s;
}
try {
@@ -60,8 +60,10 @@ public interface SingletonSessionStore<T extends Session>
s.addListener(running -> {
onStateChange(running);
});
return s;
} else {
setSessionEnabled(false);
return null;
}
} catch (Exception ex) {
setSessionEnabled(false);
@@ -56,7 +56,7 @@ public class StoreCategoryConfigComp extends SimpleComp {
var scripts = new SimpleObjectProperty<>(c.getDontAllowScripts());
var confirm = new SimpleObjectProperty<>(c.getConfirmAllModifications());
var sync = new SimpleObjectProperty<>(c.getSync());
var readOnly = new SimpleObjectProperty<>(c.getReadOnly());
var freeze = new SimpleObjectProperty<>(c.getFreezeConfigurations());
var ref = new SimpleObjectProperty<>(
c.getDefaultIdentityStore() != null
? DataStorage.get()
@@ -73,10 +73,10 @@ public class StoreCategoryConfigComp extends SimpleComp {
.nameAndDescription("categoryDontAllowScripts")
.addYesNoToggle(scripts)
.hide(!connectionsCategory)
.nameAndDescription("categoryReadOnly")
.addYesNoToggle(readOnly)
.nameAndDescription("categoryConfirmAllModifications")
.addYesNoToggle(confirm)
.nameAndDescription("categoryFreeze")
.addYesNoToggle(freeze)
.hide(!connectionsCategory)
.nameAndDescription("categoryDefaultIdentity")
.addComp(
@@ -96,7 +96,7 @@ public class StoreCategoryConfigComp extends SimpleComp {
scripts.get(),
confirm.get(),
sync.get(),
readOnly.get(),
freeze.get(),
ref.get() != null ? ref.get().get().getUuid() : null);
},
config)
@@ -226,6 +226,11 @@ public class StoreCreationModel {
validate();
commit(true);
} catch (Throwable ex) {
var changedStore = !store.getValue().equals(entry.getValue().getStore());
if (changedStore) {
int a = 0;
}
if (ex instanceof ValidationException) {
ErrorEventFactory.expected(ex);
} else if (ex instanceof StackOverflowError) {
@@ -19,7 +19,6 @@ import io.xpipe.app.hub.action.HubMenuItemProvider;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreColor;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.*;
import io.xpipe.core.process.OsType;
@@ -389,8 +388,8 @@ public abstract class StoreEntryComp extends SimpleComp {
notes.visibleProperty().bind(BindingsHelper.map(getWrapper().getNotes(), s -> s.getCommited() == null));
items.add(2, notes);
var readOnly = new MenuItem();
readOnly.graphicProperty()
var freeze = new MenuItem();
freeze.graphicProperty()
.bind(Bindings.createObjectBinding(
() -> {
var is = getWrapper().getReadOnly().get();
@@ -399,17 +398,17 @@ public abstract class StoreEntryComp extends SimpleComp {
: new FontIcon("mdi2l-lock-open-outline");
},
getWrapper().getReadOnly()));
readOnly.textProperty()
freeze.textProperty()
.bind(Bindings.createStringBinding(
() -> {
var is = getWrapper().getReadOnly().get();
return is ? AppI18n.get("unsetReadOnly") : AppI18n.get("setReadOnly");
return is ? AppI18n.get("unfreezeConfiguration") : AppI18n.get("freezeConfiguration");
},
AppI18n.activeLanguage(),
getWrapper().getReadOnly()));
readOnly.setOnAction(event ->
getWrapper().getEntry().setReadOnly(!getWrapper().getReadOnly().get()));
items.add(3, readOnly);
freeze.setOnAction(event ->
getWrapper().getEntry().setFreeze(!getWrapper().getReadOnly().get()));
items.add(freeze);
}
if (cat == StoreActionCategory.DEVELOPER) {
@@ -179,7 +179,7 @@ public class StoreEntryWrapper {
color.setValue(entry.getColor());
notes.setValue(new StoreNotes(entry.getNotes(), entry.getNotes()));
customIcon.setValue(entry.getIcon());
readOnly.setValue(entry.isReadOnly());
readOnly.setValue(entry.isFreeze());
iconFile.setValue(entry.getEffectiveIconFile());
busy.setValue(entry.getBusyCounter().get() != 0);
deletable.setValue(
@@ -880,7 +880,7 @@ public abstract class DataStorage {
public boolean getEffectiveReadOnlyState(DataStoreEntry entry) {
var cat = getStoreCategoryIfPresent(entry.getCategoryUuid()).orElseThrow();
var catConfig = getEffectiveCategoryConfig(cat);
return catConfig.getReadOnly() != null ? catConfig.getReadOnly() : entry.isReadOnly();
return catConfig.getFreezeConfigurations() != null ? catConfig.getFreezeConfigurations() : entry.isFreeze();
}
public DataStoreColor getEffectiveColor(DataStoreEntry entry) {
@@ -41,7 +41,7 @@ public class DataStoreCategoryConfig {
sync = config.sync;
}
if (readOnly == null) {
readOnly = config.readOnly;
readOnly = config.freezeConfigurations;
}
}
return new DataStoreCategoryConfig(
@@ -58,7 +58,7 @@ public class DataStoreCategoryConfig {
@With
Boolean sync;
Boolean readOnly;
Boolean freezeConfigurations;
UUID defaultIdentityStore;
}
@@ -77,7 +77,7 @@ public class DataStoreEntry extends StorageElement {
@NonFinal
@Getter
boolean readOnly;
boolean freeze;
@Getter
@NonFinal
@@ -99,7 +99,7 @@ public class DataStoreEntry extends StorageElement {
DataStoreColor color,
String notes,
String icon,
boolean readOnly,
boolean freeze,
int orderIndex) {
super(directory, uuid, name, lastUsed, lastModified, expanded, dirty);
this.color = color;
@@ -111,7 +111,7 @@ public class DataStoreEntry extends StorageElement {
this.storePersistentStateNode = storePersistentState;
this.notes = notes;
this.icon = icon;
this.readOnly = readOnly;
this.freeze = freeze;
this.orderIndex = orderIndex;
}
@@ -124,7 +124,7 @@ public class DataStoreEntry extends StorageElement {
Instant lastModified,
DataStore store,
String icon,
boolean readOnly,
boolean freeze,
int orderIndex) {
super(directory, uuid, name, lastUsed, lastModified, false, false);
this.categoryUuid = categoryUuid;
@@ -135,7 +135,7 @@ public class DataStoreEntry extends StorageElement {
this.expanded = false;
this.provider = null;
this.storePersistentStateNode = null;
this.readOnly = readOnly;
this.freeze = freeze;
this.orderIndex = orderIndex;
}
@@ -236,7 +236,7 @@ public class DataStoreEntry extends StorageElement {
}
})
.orElse(null);
var readOnly = Optional.ofNullable(json.get("readOnly"))
var freeze = Optional.ofNullable(json.get("freeze"))
.map(jsonNode -> jsonNode.booleanValue())
.orElse(false);
@@ -315,7 +315,7 @@ public class DataStoreEntry extends StorageElement {
color,
notes,
icon,
readOnly,
freeze,
orderIndex));
}
@@ -464,7 +464,7 @@ public class DataStoreEntry extends StorageElement {
obj.put("categoryUuid", categoryUuid.toString());
obj.set("color", mapper.valueToTree(color));
obj.set("icon", mapper.valueToTree(icon));
obj.put("readOnly", readOnly);
obj.put("freeze", freeze);
obj.put("orderIndex", orderIndex);
ObjectNode stateObj = JsonNodeFactory.instance.objectNode();
@@ -512,9 +512,9 @@ public class DataStoreEntry extends StorageElement {
}
}
public void setReadOnly(boolean newValue) {
var changed = readOnly != newValue;
this.readOnly = newValue;
public void setFreeze(boolean newValue) {
var changed = freeze != newValue;
this.freeze = newValue;
if (changed) {
notifyUpdate(false, true);
}
+4 -3
View File
@@ -126,7 +126,7 @@ open module io.xpipe.app {
ScanHubBatchProvider,
RunCommandInBrowserActionProvider,
RunCommandInBackgroundActionProvider,
RunCommandInTerminalActionProvider,
RunCommandInTerminalActionProvider, ComputeDirectorySizesMenuProvider,
FollowLinkMenuProvider,
BackMenuProvider,
ForwardMenuProvider,
@@ -142,6 +142,7 @@ open module io.xpipe.app {
TransferFilesActionProvider,
EditFileMenuProvider,
RunFileMenuProvider,
RenameMenuProvider,
ChmodMenuProvider,
ChownMenuProvider,
ChgrpActionProvider,
@@ -149,16 +150,16 @@ open module io.xpipe.app {
CopyMenuProvider,
CopyPathMenuProvider,
PasteMenuProvider,
CompressMenuProvider,
NewItemMenuProvider,
RenameMenuProvider,
DeleteActionProvider,
ComputeDirectorySizesActionProvider,
DeleteMenuProvider,
ChownActionProvider,
ChmodActionProvider,
TarActionProvider,
UntarActionProvider,
ZipActionProvider,
CompressMenuProvider,
UnzipActionProvider,
UnzipHereUnixMenuProvider,
UnzipDirectoryUnixMenuProvider,
@@ -2,7 +2,7 @@
.root:macos { -color-bg-default-transparent: #0d0d10D6; }
.root .button {
.root .button, .root .toggle-button {
-fx-effect: NONE;
}
@@ -1,6 +1,6 @@
.root { -color-bg-default-transparent: #FFFFFFAF; }
.root .button {
.root .button, .root .toggle-button {
-fx-effect: NONE;
}
+10 -7
View File
@@ -1,17 +1,20 @@
## Browser
## File browser
- Actions which modify a single file will now automatically refresh the file list to show updated changes
- There is now a new file browser action to compute directory sizes
- Renaming a file now moves the caret to the end of the base file name
- Fix file renaming not working if previous rename operation was cancelled
- The transfer speed in the file browser on Windows for multiple files has been optimized
## Connection hub
- You can now set connection configurations to be frozen, meaning that the connection entry can't be modified or deleted. This is helpful for templating and team vault setups
- When editing an incomplete connection configuration, the focus will automatically jump to the first incomplete/invalid value. This makes keyboard usage easier
- Password managers now support retrieving both username and password of an entry. For that, you can now create password manager identities that automatically provide the username and password
## Other
- You can now specify a git username and password in the settings menu if your local system does not have a git client with configured credentials
- You can now set connection configurations to read-only, meaning that the connection entry can't be modified or deleted. This is helpful for templating and team vault setups
- File browser actions which modify a single file will now automatically refresh the file list to show updated changes
- The transfer speed in the file browser on Windows systems has been optimized
- When editing an incomplete connection configuration, the focus will automatically jump to the first incomplete/invalid value. This makes keyboard usage easier
- Password managers now support retrieving both username and password of an entry
- You can now disable icon sources without having to remove them
- There is now a new file browser action to compute directory sizes
- Windows ARM build
+8 -3
View File
@@ -1462,13 +1462,16 @@ gitPasswordDescription=The password or personal access token to use to authentic
setReadOnly=Set read-only
unsetReadOnly=Unset read-only
readOnlyStoreError=This entry is marked as read-only. Choose a different name to save your changes to a new copy.
categoryReadOnly=Read-only connection configuration
categoryReadOnlyDescription=Marks connection configurations as read-only. This means that no existing connection entry configuration in it can be modified. New connections can be added though.
#force
categoryFreeze=Freeze connection configurations
#force
categoryFreezeDescription=Marks connection configurations as read-only. This means that no existing connection entry configuration in this category can be modified. New connections can be added though.
updateFail=Update installation did not succeed
updateFailAction=Install update manually
updateFailActionDescription=Check out the latest releases at GitHub
onePasswordPlaceholder=Item name
computeDirectorySizes=Compute directory sizes
computeSize=Compute size
vncClient=VNC client
vncClientDescription=The VNC client to launch when opening VNC connections in XPipe.\n\nYou have the option to either use the integrated VNC client within XPipe or alternatively launch an external locally installed VNC client if you are looking for more customization.
integratedXPipeVncClient=Integrated XPipe VNC client
@@ -1530,4 +1533,6 @@ moveToBottom=Move to bottom
moveToTop=Move to top
category=Category
includeRoot=Include root
excludeRoot=Exclude root
excludeRoot=Exclude root
freezeConfiguration=Freeze configuration
unfreezeConfiguration=Unfreeze configuration