mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-24 09:25:36 +00:00
Rework [stage]
This commit is contained in:
@@ -95,13 +95,7 @@ public class AppLayoutModel {
|
||||
if (prefs != null && prefs.getRequiresRestart().get()) {
|
||||
GlobalTimer.delay(
|
||||
() -> {
|
||||
if (!AppOperationMode.isInShutdown()) {
|
||||
var modal = ModalOverlay.of(
|
||||
"prefsRestartTitle", AppDialog.dialogTextKey("prefsRestartContent"));
|
||||
modal.addButton(ModalButton.cancel());
|
||||
modal.addButton(new ModalButton("restart", () -> AppRestart.restart(), true, true));
|
||||
modal.show();
|
||||
}
|
||||
showPrefsRestartDialog();
|
||||
},
|
||||
Duration.ofSeconds(1));
|
||||
AppPrefs.get().getRequiresRestart().set(false);
|
||||
@@ -120,6 +114,12 @@ public class AppLayoutModel {
|
||||
}
|
||||
});
|
||||
|
||||
AppPrefs.get().getRequiresRestart().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue && !entries.get(2).equals(selected.getValue())) {
|
||||
showPrefsRestartDialog();
|
||||
}
|
||||
});
|
||||
|
||||
var portraitExpanded = new SimpleBooleanProperty(true);
|
||||
var toggleExpand = new AppLayoutModel.QueueEntry(
|
||||
AppI18n.observable("expand"),
|
||||
@@ -151,6 +151,16 @@ public class AppLayoutModel {
|
||||
AppSizeBreakpoints.compactMode()));
|
||||
}
|
||||
|
||||
private void showPrefsRestartDialog() {
|
||||
if (!AppOperationMode.isInShutdown()) {
|
||||
var modal = ModalOverlay.of(
|
||||
"prefsRestartTitle", AppDialog.dialogTextKey("prefsRestartContent"));
|
||||
modal.addButton(ModalButton.cancel());
|
||||
modal.addButton(new ModalButton("restart", () -> AppRestart.restart(), true, true));
|
||||
modal.show();
|
||||
}
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
if (INSTANCE == null) {
|
||||
return;
|
||||
|
||||
@@ -99,42 +99,23 @@ public class StoreCategoryConfigComp extends SimpleRegionBuilder {
|
||||
: AppI18n.observable("categorySync"))
|
||||
.description("categorySyncDescription")
|
||||
.addComp(createToggle(sync, parentConfig.getSync()), sync)
|
||||
.disable(syncDisable))
|
||||
.title("connectionHandling")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("categoryDontAllowScripts")
|
||||
.addComp(createToggle(scripts, parentConfig.getDontAllowScripts()), scripts)
|
||||
.hide(!connectionsCategory)
|
||||
.nameAndDescription("categoryConfirmAllModifications")
|
||||
.addComp(createToggle(confirm, parentConfig.getConfirmAllModifications()), confirm)
|
||||
.hide(!connectionsCategory))
|
||||
.title("connectionConfiguration")
|
||||
.sub(new OptionsBuilder()
|
||||
.nameAndDescription("categoryFreeze")
|
||||
.addComp(createToggle(freeze, parentConfig.getFreezeConfigurations()), freeze)
|
||||
.hide(!connectionsCategory)
|
||||
.nameAndDescription("categoryDefaultIdentity")
|
||||
.addComp(
|
||||
new StoreChoiceComp<>(
|
||||
null,
|
||||
identityRef,
|
||||
DataStore.class,
|
||||
null,
|
||||
StoreViewState.get().getAllIdentitiesCategory(),
|
||||
DataStoreCreationCategory.IDENTITY),
|
||||
identityRef)
|
||||
.hide(!connectionsCategory)
|
||||
.nameAndDescription("categoryDefaultGateway")
|
||||
.addComp(
|
||||
new StoreChoiceComp<>(
|
||||
null,
|
||||
gatewayRef,
|
||||
DataStore.class,
|
||||
null,
|
||||
StoreViewState.get().getAllConnectionsCategory(),
|
||||
DataStoreCreationCategory.HOST),
|
||||
gatewayRef)
|
||||
.hide(!connectionsCategory))
|
||||
.disable(syncDisable));
|
||||
if (connectionsCategory) {
|
||||
options.title("connectionConfiguration").sub(new OptionsBuilder()
|
||||
.nameAndDescription("categoryDefaultIdentity")
|
||||
.addComp(new StoreChoiceComp<>(null, identityRef, DataStore.class, null, StoreViewState.get().getAllIdentitiesCategory(),
|
||||
DataStoreCreationCategory.IDENTITY), identityRef)
|
||||
.nameAndDescription("categoryDefaultGateway")
|
||||
.addComp(new StoreChoiceComp<>(null, gatewayRef, DataStore.class, null, StoreViewState.get().getAllConnectionsCategory(),
|
||||
DataStoreCreationCategory.HOST), gatewayRef));
|
||||
|
||||
options.title("connectionHandling").sub(new OptionsBuilder().nameAndDescription("categoryDontAllowScripts")
|
||||
.addComp(createToggle(scripts, parentConfig.getDontAllowScripts()), scripts)
|
||||
.nameAndDescription("categoryConfirmAllModifications")
|
||||
.addComp(createToggle(confirm, parentConfig.getConfirmAllModifications()), confirm).nameAndDescription("categoryFreeze")
|
||||
.addComp(createToggle(freeze, parentConfig.getFreezeConfigurations()), freeze));
|
||||
}
|
||||
options
|
||||
.bind(
|
||||
() -> {
|
||||
return new DataStoreCategoryConfig(
|
||||
|
||||
@@ -43,7 +43,7 @@ public class StoreCreationModel {
|
||||
ObservableValue<DataStoreEntry> entry;
|
||||
BooleanProperty skippable = new SimpleBooleanProperty();
|
||||
BooleanProperty connectable = new SimpleBooleanProperty();
|
||||
StringProperty name;
|
||||
Property<String> name;
|
||||
DataStoreEntry existingEntry;
|
||||
List<DataStore> existingDependencies;
|
||||
boolean staticDisplay;
|
||||
|
||||
@@ -57,7 +57,6 @@ public class DenseStoreEntryComp extends StoreEntryComp {
|
||||
grid.widthProperty()));
|
||||
var notes = new StoreNotesComp(getWrapper()).build();
|
||||
var templateIcon = createTemplateIcon().build();
|
||||
var userIcon = createScopeIcon().build();
|
||||
var pinIcon = createPinIcon().build();
|
||||
var info = createInformation().build();
|
||||
var active = new StoreActiveComp(getWrapper()).build();
|
||||
@@ -137,7 +136,7 @@ public class DenseStoreEntryComp extends StoreEntryComp {
|
||||
nameBoxEntries.add(name);
|
||||
nameBoxEntries.add(new Spacer(2, Orientation.HORIZONTAL));
|
||||
nameBoxEntries.add(tags);
|
||||
nameBoxEntries.addAll(List.of(index, active, templateIcon, userIcon, pinIcon, notes));
|
||||
nameBoxEntries.addAll(List.of(index, active, templateIcon, pinIcon, notes));
|
||||
var nameBox = new HBox(nameBoxEntries.toArray(Node[]::new));
|
||||
nameBox.setSpacing(4);
|
||||
nameBox.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
@@ -139,22 +139,6 @@ public interface StoreEntryBadge {
|
||||
return of("mdi2a-account", s);
|
||||
}
|
||||
|
||||
static StoreEntryBadge ofUsername(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return of("mdi2a-account", s).withCopyAction();
|
||||
}
|
||||
|
||||
static StoreEntryBadge ofUsername(String display, String copy) {
|
||||
if (display == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return of("mdi2a-account", display).withCopyAction(copy);
|
||||
}
|
||||
|
||||
static StoreEntryBadge ofPassword(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
|
||||
@@ -19,7 +19,7 @@ public class StoreNotesComp extends RegionBuilder<Button> {
|
||||
var prop = new SimpleStringProperty(initial);
|
||||
var md = new MarkdownEditorComp(prop, "notes-" + wrapper.getName().getValue())
|
||||
.prefWidth(700)
|
||||
.prefHeight(800);
|
||||
.maxHeight(800);
|
||||
|
||||
var modal = ModalOverlay.of(new ReadOnlyStringWrapper(wrapper.getName().getValue()), md, null);
|
||||
if (wrapper.getNotes().getValue() != null) {
|
||||
@@ -32,7 +32,6 @@ public class StoreNotesComp extends RegionBuilder<Button> {
|
||||
true,
|
||||
false));
|
||||
}
|
||||
modal.addButton(new ModalButton("cancel", () -> {}, true, false));
|
||||
modal.addButton(new ModalButton(
|
||||
"apply",
|
||||
() -> {
|
||||
|
||||
@@ -74,6 +74,11 @@ public class ErrorEventFactory {
|
||||
return "Invalid file path: " + ipe.getMessage();
|
||||
}
|
||||
|
||||
if (t instanceof UnsatisfiedLinkError ule) {
|
||||
// Don't include full PATH variable in message
|
||||
return ule.getMessage().split(":")[0];
|
||||
}
|
||||
|
||||
if (t instanceof InvocationTargetException ite && ite.getCause() != null && ite.getCause() != t) {
|
||||
return formatThrowableMessage(ite.getCause());
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.xpipe.app.comp.SimpleRegionBuilder;
|
||||
import io.xpipe.app.comp.base.*;
|
||||
import io.xpipe.app.core.App;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.platform.BindingsHelper;
|
||||
import io.xpipe.app.platform.DerivedObservableList;
|
||||
import io.xpipe.app.platform.LabelGraphic;
|
||||
@@ -54,6 +55,10 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
|
||||
this.showSettings = showSettings;
|
||||
}
|
||||
|
||||
protected void selectFromList(PasswordManager.ListEntry entry) {
|
||||
value.setValue(entry.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var prefs = AppPrefs.get();
|
||||
@@ -87,7 +92,15 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
|
||||
struc.setDisable(true);
|
||||
status.set(" " + AppI18n.get("querying"));
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
var list = PasswordManagerKeyList.queryList(false);
|
||||
List<PasswordManager.ListEntry> list;
|
||||
try {
|
||||
list = PasswordManagerKeyList.queryList(false);
|
||||
} catch (Exception e) {
|
||||
struc.setDisable(false);
|
||||
status.set(null);
|
||||
ErrorEventFactory.fromThrowable(e).handle();
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
struc.setDisable(false);
|
||||
@@ -134,7 +147,7 @@ public class PasswordManagerTestComp extends SimpleRegionBuilder {
|
||||
var buttonName = entry.getTitle();
|
||||
var entryButton = new ButtonComp(new ReadOnlyObjectWrapper<>(buttonName), () -> {
|
||||
popover.hide();
|
||||
value.setValue(entry.getKey());
|
||||
selectFromList(entry);
|
||||
});
|
||||
entryButton.maxWidth(400);
|
||||
entryButton.style(Styles.FLAT);
|
||||
|
||||
@@ -32,6 +32,8 @@ public interface DataStorageAccessHandler {
|
||||
|
||||
boolean isAccessRestricted();
|
||||
|
||||
boolean isAccessSubRestricted();
|
||||
|
||||
boolean isAccessible();
|
||||
|
||||
DataStorageAccessType getType();
|
||||
|
||||
@@ -132,7 +132,7 @@ public abstract class DataStorageElement {
|
||||
|
||||
public abstract boolean isInStorage();
|
||||
|
||||
public abstract Path[] getShareableFiles();
|
||||
public abstract List<Path> getSyncableFiles();
|
||||
|
||||
public void notifyUpdate(boolean used, boolean modified) {
|
||||
if (used) {
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DataStoreAccessScopeComp extends SimpleRegionBuilder {
|
||||
var handler = DataStorageAccessHandler.getInstance();
|
||||
var auth = handler.getType();
|
||||
|
||||
if (auth != DataStorageAccessType.ROLE || !handler.isAccessible()) {
|
||||
if (auth != DataStorageAccessType.ROLE || !handler.isAccessible() || !handler.isAccessSubRestricted()) {
|
||||
var l = new LabelComp(AppI18n.observable("unavailable"));
|
||||
|
||||
var settings = new ButtonComp(null, new FontIcon("mdomz-settings"), () -> {
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.*;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
@@ -262,8 +263,8 @@ public class DataStoreCategory extends DataStorageElement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] getShareableFiles() {
|
||||
return new Path[] {directory.resolve("category.json")};
|
||||
public List<Path> getSyncableFiles() {
|
||||
return List.of(directory.resolve("category.json"));
|
||||
}
|
||||
|
||||
public void writeDataToDisk() throws Exception {
|
||||
|
||||
@@ -529,11 +529,10 @@ public class DataStoreEntry extends DataStorageElement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] getShareableFiles() {
|
||||
var notes = directory.resolve("notes.md");
|
||||
var list = List.of(directory.resolve("store.json"), directory.resolve("entry.json"));
|
||||
return Stream.concat(list.stream(), Files.exists(notes) ? Stream.of(notes) : Stream.of())
|
||||
.toArray(Path[]::new);
|
||||
public List<Path> getSyncableFiles() {
|
||||
var list = List.of(directory.resolve("store.json"), directory.resolve("entry.json"),
|
||||
directory.resolve("notes.md"), directory.resolve("notes.json"));
|
||||
return list;
|
||||
}
|
||||
|
||||
public boolean isAccessible() {
|
||||
@@ -594,14 +593,14 @@ public class DataStoreEntry extends DataStorageElement {
|
||||
Files.writeString(directory.resolve("entry.json"), this.entryNode.getWriteString());
|
||||
}
|
||||
|
||||
var normalNotesFile = directory.resolve("notes.md");
|
||||
var encryptedNotesFile = directory.resolve("notes.json");
|
||||
Files.deleteIfExists(normalNotesFile);
|
||||
Files.deleteIfExists(encryptedNotesFile);
|
||||
this.notesNode = this.notesNode != null ? this.notesNode.prepareForWrite(this, false, getNotes()) : null;
|
||||
if (this.notesNode != null && this.notesNode.requiresWrite()) {
|
||||
var normalNotesFile = directory.resolve("notes.md");
|
||||
var encryptedNotesFile = directory.resolve("notes.json");
|
||||
Files.deleteIfExists(normalNotesFile);
|
||||
Files.deleteIfExists(encryptedNotesFile);
|
||||
var file = this.notesNode.isEncrypted() ? encryptedNotesFile : normalNotesFile;
|
||||
Files.writeString(file, this.notesNode.getWriteString());
|
||||
Files.writeString(file, this.notesNode.isEncrypted() ? this.notesNode.getWriteString() : this.notesNode.getValue());
|
||||
}
|
||||
|
||||
this.storeNode = this.storeNode.prepareForWrite(this, true, getStore());
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StandardStorage extends DataStorage {
|
||||
|
||||
@@ -104,7 +103,7 @@ public class StandardStorage extends DataStorage {
|
||||
}
|
||||
|
||||
for (DataStoreCategory cat : new ArrayList<>(storeCategories)) {
|
||||
if (Arrays.stream(cat.getShareableFiles()).noneMatch(Files::exists)) {
|
||||
if (cat.getSyncableFiles().stream().noneMatch(Files::exists)) {
|
||||
deleteStoreCategory(cat, false, false);
|
||||
}
|
||||
}
|
||||
@@ -155,7 +154,7 @@ public class StandardStorage extends DataStorage {
|
||||
selectedCategory = getStoreCategoryIfPresent(DEFAULT_CATEGORY_UUID).orElseThrow();
|
||||
|
||||
for (DataStoreEntry entry : new ArrayList<>(getStoreEntries())) {
|
||||
if (Arrays.stream(entry.getShareableFiles()).noneMatch(Files::exists)) {
|
||||
if (entry.getSyncableFiles().stream().noneMatch(Files::exists)) {
|
||||
deleteStoreEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class WebtopDisplayScale {
|
||||
initialScale = clamped;
|
||||
} else if (!initialScale.equals(clamped)) {
|
||||
AppPrefs.get().uiScale.setValue(clamped);
|
||||
AppRestart.restart();
|
||||
AppPrefs.get().getRequiresRestart().set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,6 @@ public abstract class IdentityStoreProvider implements DataStoreProvider {
|
||||
var password = st.getPassword() == null || st.getPassword() instanceof SecretNoneStrategy ? null : "Password";
|
||||
var key = st.getSshIdentity() == null || st.getSshIdentity() instanceof NoIdentityStrategy ? null : "Key";
|
||||
return StoreEntryInformation.of(
|
||||
StoreEntryBadge.ofUsername(user), StoreEntryBadge.ofPassword(password), StoreEntryBadge.ofKey(key));
|
||||
StoreEntryBadge.ofAuth(user), StoreEntryBadge.ofPassword(password), StoreEntryBadge.ofKey(key));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user