mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-26 18:35:43 +00:00
Rework
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+41
@@ -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();
|
||||
|
||||
+11
-17
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+10
-7
@@ -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
|
||||
|
||||
Generated
+8
-3
@@ -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
|
||||
Reference in New Issue
Block a user