Small bugfixes and refactor

This commit is contained in:
crschnick 2023-10-19 16:52:35 +00:00
parent e78dba1f2e
commit 1f3afa3ad4
52 changed files with 227 additions and 167 deletions

View file

@ -1,15 +1,16 @@
package io.xpipe.app.browser; package io.xpipe.app.browser;
import atlantafx.base.theme.Styles; import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.comp.storage.store.StoreSection; import io.xpipe.app.comp.store.StoreSection;
import io.xpipe.app.comp.storage.store.StoreSectionMiniComp; import io.xpipe.app.comp.store.StoreSectionMiniComp;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFont;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.FilterComp; import io.xpipe.app.fxcomps.impl.FilterComp;
import io.xpipe.app.fxcomps.impl.HorizontalComp; import io.xpipe.app.fxcomps.impl.HorizontalComp;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.BooleanScope;
import io.xpipe.app.util.DataStoreCategoryChoiceComp; import io.xpipe.app.util.DataStoreCategoryChoiceComp;
import io.xpipe.app.util.FixedHierarchyStore; import io.xpipe.app.util.FixedHierarchyStore;
@ -91,7 +92,7 @@ final class BrowserBookmarkList extends SimpleComp {
}); });
}); });
}); });
var category = new DataStoreCategoryChoiceComp(StoreViewState.get().getActiveCategory()) var category = new DataStoreCategoryChoiceComp(DataStorage.get().getAllConnectionsCategory(), StoreViewState.get().getActiveCategory())
.styleClass(Styles.LEFT_PILL) .styleClass(Styles.LEFT_PILL)
.grow(false, true); .grow(false, true);
var filter = var filter =

View file

@ -392,8 +392,11 @@ public final class OpenFileSystemModel {
if (entry.getStore() instanceof ShellStore s) { if (entry.getStore() instanceof ShellStore s) {
var connection = ((ConnectionFileSystem) fileSystem).getShellControl(); var connection = ((ConnectionFileSystem) fileSystem).getShellControl();
var name = directory + " - " + entry.get().getName(); var name = directory + " - " + entry.get().getName();
var toOpen = ProcessControlProvider.get().withDefaultScripts(s.control()); var toOpen = ProcessControlProvider.get().withDefaultScripts(connection);
TerminalHelper.open(entry.getEntry(), name, toOpen.initWith(connection.getShellDialect().getCdCommand(directory))); TerminalHelper.open(entry.getEntry(), name, toOpen.initWith(connection.getShellDialect().getCdCommand(directory)));
// Restart connection as we will have to start it anyway, so we speed it up by doing it preemptively
connection.start();
} }
}); });
}); });

View file

@ -1,6 +1,6 @@
package io.xpipe.app.comp.base; package io.xpipe.app.comp.base;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.core.AppResources; import io.xpipe.app.core.AppResources;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.fxcomps.impl.PrettyImageHelper;

View file

@ -54,6 +54,23 @@ public class SideMenuBarComp extends Comp<CompStructure<VBox>> {
vbox.getChildren().add(b.createRegion()); vbox.getChildren().add(b.createRegion());
}); });
{
var b = new IconButtonComp(
"mdal-bug_report",
() -> {
var event = ErrorEvent.fromMessage("User Report");
if (AppLogs.get().isWriteToFile()) {
event.attachment(AppLogs.get().getSessionLogsDirectory());
}
UserReportComp.show(event.build());
})
.apply(new FancyTooltipAugment<>("reportIssue"));
b.apply(struc -> {
AppFont.setSize(struc.get(), 2);
});
vbox.getChildren().add(b.createRegion());
}
{ {
var b = new IconButtonComp("mdi2g-github", () -> Hyperlinks.open(Hyperlinks.GITHUB)) var b = new IconButtonComp("mdi2g-github", () -> Hyperlinks.open(Hyperlinks.GITHUB))
.apply(new FancyTooltipAugment<>("visitGithubRepository")); .apply(new FancyTooltipAugment<>("visitGithubRepository"));
@ -64,25 +81,18 @@ public class SideMenuBarComp extends Comp<CompStructure<VBox>> {
} }
{ {
var b = new IconButtonComp( var b = new IconButtonComp("mdi2c-comment-processing-outline", () -> Hyperlinks.open(Hyperlinks.ROADMAP))
"mdal-bug_report", .apply(new FancyTooltipAugment<>("roadmap"));
() -> {
var event = ErrorEvent.fromMessage("User Report");
if (AppLogs.get().isWriteToFile()) {
event.attachment(AppLogs.get().getSessionLogsDirectory());
}
UserReportComp.show(event.build());
})
.apply(new FancyTooltipAugment<>("reportIssue"));
b.apply(struc -> { b.apply(struc -> {
AppFont.setSize(struc.get(), 2); AppFont.setSize(struc.get(), 2);
}); });
vbox.getChildren().add(b.createRegion()); vbox.getChildren().add(b.createRegion());
} }
{ {
var b = new IconButtonComp("mdi2c-comment-processing-outline", () -> Hyperlinks.open(Hyperlinks.ROADMAP)) var b = new IconButtonComp("mdi2d-discord", () -> Hyperlinks.open(Hyperlinks.DISCORD))
.apply(new FancyTooltipAugment<>("roadmap")); .apply(new FancyTooltipAugment<>("discord"));
b.apply(struc -> { b.apply(struc -> {
AppFont.setSize(struc.get(), 2); AppFont.setSize(struc.get(), 2);
}); });

View file

@ -1,6 +1,6 @@
package io.xpipe.app.comp.base; package io.xpipe.app.comp.base;
import io.xpipe.app.comp.storage.store.StoreSection; import io.xpipe.app.comp.store.StoreSection;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.BindingsHelper;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.comp.base; package io.xpipe.app.comp.base;
import atlantafx.base.theme.Styles; import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFont;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;

View file

@ -25,6 +25,7 @@ import io.xpipe.core.store.DataStore;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
@ -52,9 +53,10 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
Property<Validator> validator = new SimpleObjectProperty<>(new SimpleValidator()); Property<Validator> validator = new SimpleObjectProperty<>(new SimpleValidator());
Property<String> messageProp = new SimpleStringProperty(); Property<String> messageProp = new SimpleStringProperty();
BooleanProperty finished = new SimpleBooleanProperty(); BooleanProperty finished = new SimpleBooleanProperty();
Property<DataStoreEntry> entry = new SimpleObjectProperty<>(); ObservableValue<DataStoreEntry> entry;
BooleanProperty changedSinceError = new SimpleBooleanProperty(); BooleanProperty changedSinceError = new SimpleBooleanProperty();
StringProperty name; StringProperty name;
DataStoreEntry existingEntry;
boolean exists; boolean exists;
boolean staticDisplay; boolean staticDisplay;
@ -64,13 +66,14 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
Property<DataStore> store, Property<DataStore> store,
Predicate<DataStoreProvider> filter, Predicate<DataStoreProvider> filter,
String initialName, String initialName,
boolean exists, DataStoreEntry existingEntry, boolean exists,
boolean staticDisplay) { boolean staticDisplay) {
this.parent = parent; this.parent = parent;
this.provider = provider; this.provider = provider;
this.store = store; this.store = store;
this.filter = filter; this.filter = filter;
this.name = new SimpleStringProperty(initialName != null && !initialName.isEmpty() ? initialName : null); this.name = new SimpleStringProperty(initialName != null && !initialName.isEmpty() ? initialName : null);
this.existingEntry = existingEntry;
this.exists = exists; this.exists = exists;
this.staticDisplay = staticDisplay; this.staticDisplay = staticDisplay;
this.store.addListener((c, o, n) -> { this.store.addListener((c, o, n) -> {
@ -98,6 +101,27 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
newValue.validate(); newValue.validate();
}); });
}); });
this.entry = Bindings.createObjectBinding(() -> {
if (name.getValue() == null || store.getValue() == null) {
return null;
}
var testE = DataStoreEntry.createNew(
UUID.randomUUID(),
DataStorage.get().getSelectedCategory().getUuid(),
name.getValue(),
store.getValue());
var p = provider.getValue().getDisplayParent(testE);
return DataStoreEntry.createNew(
UUID.randomUUID(),
p != null
? p.getCategoryUuid()
: DataStorage.get()
.getSelectedCategory()
.getUuid(),
name.getValue(),
store.getValue());
}, name, store);
} }
public static void showEdit(DataStoreEntry e) { public static void showEdit(DataStoreEntry e) {
@ -116,7 +140,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
}); });
}, },
true, true,
true); true,
e);
} }
public static void showCreation(DataStoreProvider selected, Predicate<DataStoreProvider> filter) { public static void showCreation(DataStoreProvider selected, Predicate<DataStoreProvider> filter) {
@ -136,17 +161,19 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
} }
}, },
false, false,
false); false,
null);
} }
public static void show( private static void show(
String initialName, String initialName,
DataStoreProvider provider, DataStoreProvider provider,
DataStore s, DataStore s,
Predicate<DataStoreProvider> filter, Predicate<DataStoreProvider> filter,
Consumer<DataStoreEntry> con, Consumer<DataStoreEntry> con,
boolean exists, boolean exists,
boolean staticDisplay) { boolean staticDisplay,
DataStoreEntry existingEntry) {
var prop = new SimpleObjectProperty<>(provider); var prop = new SimpleObjectProperty<>(provider);
var store = new SimpleObjectProperty<>(s); var store = new SimpleObjectProperty<>(s);
var loading = new SimpleBooleanProperty(); var loading = new SimpleBooleanProperty();
@ -158,7 +185,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
return new MultiStepComp() { return new MultiStepComp() {
private final GuiDsStoreCreator creator = new GuiDsStoreCreator( private final GuiDsStoreCreator creator = new GuiDsStoreCreator(
this, prop, store, filter, initialName, exists, staticDisplay); this, prop, store, filter, initialName, existingEntry, exists, staticDisplay);
@Override @Override
protected List<Entry> setup() { protected List<Entry> setup() {
@ -223,29 +250,6 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
.description("connectionNameDescription") .description("connectionNameDescription")
.addString(name, false) .addString(name, false)
.nonNull(propVal) .nonNull(propVal)
.bind(
() -> {
if (name.getValue() == null || store.getValue() == null) {
return null;
}
var testE = DataStoreEntry.createNew(
UUID.randomUUID(),
DataStorage.get().getSelectedCategory().getUuid(),
name.getValue(),
store.getValue());
var parent = provider.getValue().getDisplayParent(testE);
return DataStoreEntry.createNew(
UUID.randomUUID(),
parent != null
? parent.getCategoryUuid()
: DataStorage.get()
.getSelectedCategory()
.getUuid(),
name.getValue(),
store.getValue());
},
entry)
.build(); .build();
} }
@ -268,15 +272,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
SimpleChangeListener.apply(provider, n -> { SimpleChangeListener.apply(provider, n -> {
if (n != null) { if (n != null) {
// var install = n.getRequiredAdditionalInstallation(); var d = n.guiDialog(existingEntry, store);
// if (install != null && AppExtensionManager.getInstance().isInstalled(install)) {
// layout.setCenter(new InstallExtensionComp((DownloadModuleInstall)
// install).createRegion());
// validator.setValue(new SimpleValidator());
// return;
// }
var d = n.guiDialog(entry.getValue(), store);
var propVal = new SimpleValidator(); var propVal = new SimpleValidator();
var propR = createStoreProperties(d == null || d.getComp() == null ? null : d.getComp(), propVal); var propR = createStoreProperties(d == null || d.getComp() == null ? null : d.getComp(), propVal);

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import javafx.geometry.HPos; import javafx.geometry.HPos;

View file

@ -1,10 +1,9 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;
import javafx.application.Platform;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
@ -67,7 +66,7 @@ public class StoreCategoryWrapper {
} }
public void select() { public void select() {
Platform.runLater(() -> { PlatformThread.runLaterIfNeeded(() -> {
StoreViewState.get().getActiveCategory().setValue(this); StoreViewState.get().getActiveCategory().setValue(this);
}); });
} }

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.comp.store.GuiDsStoreCreator; import io.xpipe.app.comp.store.GuiDsStoreCreator;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import atlantafx.base.theme.Styles; import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.base.LoadingOverlayComp; import io.xpipe.app.comp.base.LoadingOverlayComp;
@ -345,7 +345,7 @@ public abstract class StoreEntryComp extends SimpleComp {
if (wrapper.getEntry().getProvider() != null && wrapper.getEntry().getProvider().canMoveCategories()) { if (wrapper.getEntry().getProvider() != null && wrapper.getEntry().getProvider().canMoveCategories()) {
var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline")); var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline"));
StoreViewState.get().getSortedCategories().forEach(storeCategoryWrapper -> { StoreViewState.get().getSortedCategories(DataStorage.get().getRootCategory(DataStorage.get().getStoreCategoryIfPresent(wrapper.getEntry().getCategoryUuid()).orElseThrow())).forEach(storeCategoryWrapper -> {
MenuItem m = new MenuItem(storeCategoryWrapper.getName()); MenuItem m = new MenuItem(storeCategoryWrapper.getName());
m.setOnAction(event -> { m.setOnAction(event -> {
wrapper.moveTo(storeCategoryWrapper.getCategory()); wrapper.moveTo(storeCategoryWrapper.getCategory());

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.comp.base.MultiContentComp; import io.xpipe.app.comp.base.MultiContentComp;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.comp.base.CountComp; import io.xpipe.app.comp.base.CountComp;
import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFont;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.comp.store.GuiDsStoreCreator; import io.xpipe.app.comp.store.GuiDsStoreCreator;
import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.ext.ActionProvider;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.core.AppActionLinkDetector; import io.xpipe.app.core.AppActionLinkDetector;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.BindingsHelper;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.ListBoxViewComp;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;

View file

@ -1,4 +1,4 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;

View file

@ -1,6 +1,7 @@
package io.xpipe.app.comp.storage.store; package io.xpipe.app.comp.store;
import io.xpipe.app.core.AppCache; import io.xpipe.app.core.AppCache;
import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreCategory;
@ -47,14 +48,14 @@ public class StoreViewState {
tl = StoreSection.createTopLevel(allEntries, storeEntryWrapper -> true, filter, activeCategory); tl = StoreSection.createTopLevel(allEntries, storeEntryWrapper -> true, filter, activeCategory);
} catch (Exception exception) { } catch (Exception exception) {
tl = new StoreSection(null, FXCollections.emptyObservableList(), FXCollections.emptyObservableList(), 0); tl = new StoreSection(null, FXCollections.emptyObservableList(), FXCollections.emptyObservableList(), 0);
categories.setAll(new StoreCategoryWrapper(DataStorage.get().getAllCategory())); categories.setAll(new StoreCategoryWrapper(DataStorage.get().getAllConnectionsCategory()));
activeCategory.setValue(getAllConnectionsCategory()); activeCategory.setValue(getAllConnectionsCategory());
ErrorEvent.fromThrowable(exception).handle(); ErrorEvent.fromThrowable(exception).handle();
} }
currentTopLevelSection = tl; currentTopLevelSection = tl;
} }
public ObservableList<StoreCategoryWrapper> getSortedCategories() { public ObservableList<StoreCategoryWrapper> getSortedCategories(DataStoreCategory root) {
Comparator<StoreCategoryWrapper> comparator = new Comparator<>() { Comparator<StoreCategoryWrapper> comparator = new Comparator<>() {
@Override @Override
public int compare(StoreCategoryWrapper o1, StoreCategoryWrapper o2) { public int compare(StoreCategoryWrapper o1, StoreCategoryWrapper o2) {
@ -89,7 +90,7 @@ public class StoreViewState {
return o1.getName().compareToIgnoreCase(o2.getName()); return o1.getName().compareToIgnoreCase(o2.getName());
} }
}; };
return categories.sorted(comparator); return BindingsHelper.filteredContentBinding(categories, cat-> root == null || cat.getRoot().equals(root)).sorted(comparator);
} }
public StoreCategoryWrapper getAllConnectionsCategory() { public StoreCategoryWrapper getAllConnectionsCategory() {

View file

@ -3,7 +3,7 @@ package io.xpipe.app.core;
import io.xpipe.app.browser.BrowserComp; import io.xpipe.app.browser.BrowserComp;
import io.xpipe.app.browser.BrowserModel; import io.xpipe.app.browser.BrowserModel;
import io.xpipe.app.comp.DeveloperTabComp; import io.xpipe.app.comp.DeveloperTabComp;
import io.xpipe.app.comp.storage.store.StoreLayoutComp; import io.xpipe.app.comp.store.StoreLayoutComp;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.prefs.PrefsComp; import io.xpipe.app.prefs.PrefsComp;
import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.LicenseProvider;

View file

@ -14,6 +14,7 @@ import javafx.animation.KeyFrame;
import javafx.animation.KeyValue; import javafx.animation.KeyValue;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform;
import javafx.css.PseudoClass; import javafx.css.PseudoClass;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
@ -41,7 +42,8 @@ public class AppTheme {
} }
SimpleChangeListener.apply(AppPrefs.get().theme, t -> { SimpleChangeListener.apply(AppPrefs.get().theme, t -> {
Theme.ALL.forEach(theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId())); Theme.ALL.forEach(
theme -> stage.getScene().getRoot().getStyleClass().remove(theme.getCssId()));
if (t == null) { if (t == null) {
return; return;
} }
@ -51,7 +53,7 @@ public class AppTheme {
stage.getScene().getRoot().pseudoClassStateChanged(DARK, t.isDark()); stage.getScene().getRoot().pseudoClassStateChanged(DARK, t.isDark());
}); });
SimpleChangeListener.apply(AppPrefs.get().performanceMode(),val -> { SimpleChangeListener.apply(AppPrefs.get().performanceMode(), val -> {
stage.getScene().getRoot().pseudoClassStateChanged(PRETTY, !val); stage.getScene().getRoot().pseudoClassStateChanged(PRETTY, !val);
stage.getScene().getRoot().pseudoClassStateChanged(PERFORMANCE, val); stage.getScene().getRoot().pseudoClassStateChanged(PERFORMANCE, val);
}); });
@ -111,29 +113,30 @@ public class AppTheme {
} }
PlatformThread.runLaterIfNeeded(() -> { PlatformThread.runLaterIfNeeded(() -> {
for (Window window : Window.getWindows()) { var window = AppMainWindow.getInstance().getStage();
var scene = window.getScene(); var scene = window.getScene();
Image snapshot = scene.snapshot(null); Pane root = (Pane) scene.getRoot();
Pane root = (Pane) scene.getRoot(); Image snapshot = scene.snapshot(null);
ImageView imageView = new ImageView(snapshot);
root.getChildren().add(imageView);
ImageView imageView = new ImageView(snapshot); newTheme.apply();
root.getChildren().add(imageView); TrackEvent.debug("Set theme " + newTheme.getId() + " for scene");
Platform.runLater(() -> {
// Animate! // Animate!
var transition = new Timeline( var transition = new Timeline(
new KeyFrame( new KeyFrame(
Duration.ZERO, new KeyValue(imageView.opacityProperty(), 1, Interpolator.EASE_OUT)), Duration.millis(0),
new KeyValue(imageView.opacityProperty(), 1, Interpolator.EASE_OUT)),
new KeyFrame( new KeyFrame(
Duration.millis(1250), Duration.millis(600),
new KeyValue(imageView.opacityProperty(), 0, Interpolator.EASE_OUT))); new KeyValue(imageView.opacityProperty(), 0, Interpolator.EASE_OUT)));
transition.setOnFinished(e -> { transition.setOnFinished(e -> {
root.getChildren().remove(imageView); root.getChildren().remove(imageView);
}); });
transition.play(); transition.play();
} });
newTheme.apply();
TrackEvent.debug("Set theme " + newTheme.getId() + " for scene");
}); });
} }
@ -150,14 +153,18 @@ public class AppTheme {
@SneakyThrows @SneakyThrows
public void apply() { public void apply() {
var builder = new StringBuilder(); var builder = new StringBuilder();
AppResources.with(AppResources.XPIPE_MODULE, "theme/" + id + ".css", path->{ AppResources.with(AppResources.XPIPE_MODULE, "theme/" + id + ".css", path -> {
var content = Files.readString(path); var content = Files.readString(path);
builder.append(content); builder.append(content);
}); });
AppResources.with("atlantafx.base", theme.getUserAgentStylesheet(), path->{ AppResources.with("atlantafx.base", theme.getUserAgentStylesheet(), path -> {
var baseStyleContent = Files.readString(path); var baseStyleContent = Files.readString(path);
builder.append("\n").append(baseStyleContent.lines().skip(builder.toString().lines().count()).collect(Collectors.joining("\n"))); builder.append("\n")
.append(baseStyleContent
.lines()
.skip(builder.toString().lines().count())
.collect(Collectors.joining("\n")));
}); });
var out = Files.createTempFile(id, ".css"); var out = Files.createTempFile(id, ".css");
@ -166,7 +173,6 @@ public class AppTheme {
Application.setUserAgentStylesheet(out.toUri().toString()); Application.setUserAgentStylesheet(out.toUri().toString());
} }
@Override @Override
public String toTranslatedString() { public String toTranslatedString() {
return name; return name;
@ -188,7 +194,8 @@ public class AppTheme {
public static final Theme CUSTOM = new DerivedTheme("custom", "primer", "Custom", new PrimerDark()); public static final Theme CUSTOM = new DerivedTheme("custom", "primer", "Custom", new PrimerDark());
// Also include your custom theme here // Also include your custom theme here
public static final List<Theme> ALL = List.of(PRIMER_LIGHT, PRIMER_DARK, NORD_LIGHT, NORD_DARK, CUPERTINO_LIGHT, CUPERTINO_DARK, DRACULA); public static final List<Theme> ALL =
List.of(PRIMER_LIGHT, PRIMER_DARK, NORD_LIGHT, NORD_DARK, CUPERTINO_LIGHT, CUPERTINO_DARK, DRACULA);
static Theme getDefaultLightTheme() { static Theme getDefaultLightTheme() {
return switch (OsType.getLocal()) { return switch (OsType.getLocal()) {
@ -207,14 +214,16 @@ public class AppTheme {
} }
protected final String id; protected final String id;
@Getter @Getter
protected final String cssId; protected final String cssId;
protected final atlantafx.base.theme.Theme theme; protected final atlantafx.base.theme.Theme theme;
public boolean isDark() { public boolean isDark() {
return theme.isDarkMode(); return theme.isDarkMode();
} }
public void apply() { public void apply() {
Application.setUserAgentStylesheet(theme.getUserAgentStylesheet()); Application.setUserAgentStylesheet(theme.getUserAgentStylesheet());
} }

View file

@ -1,7 +1,7 @@
package io.xpipe.app.core.mode; package io.xpipe.app.core.mode;
import io.xpipe.app.browser.BrowserModel; import io.xpipe.app.browser.BrowserModel;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.*; import io.xpipe.app.core.*;
import io.xpipe.app.issue.*; import io.xpipe.app.issue.*;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;

View file

@ -1,6 +1,6 @@
package io.xpipe.app.core.mode; package io.xpipe.app.core.mode;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.*; import io.xpipe.app.core.*;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;

View file

@ -1,10 +1,10 @@
package io.xpipe.app.ext; package io.xpipe.app.ext;
import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.comp.base.MarkdownComp;
import io.xpipe.app.comp.storage.store.StoreEntryComp; import io.xpipe.app.comp.store.StoreEntryComp;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.comp.storage.store.StoreSection; import io.xpipe.app.comp.store.StoreSection;
import io.xpipe.app.comp.storage.store.StoreSectionComp; import io.xpipe.app.comp.store.StoreSectionComp;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppImages; import io.xpipe.app.core.AppImages;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
@ -105,10 +105,6 @@ public interface DataStoreProvider {
return null; return null;
} }
default DataStoreEntry getLogicalParent(DataStoreEntry store) {
return getDisplayParent(store);
}
default GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) { default GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
return null; return null;
} }

View file

@ -3,7 +3,7 @@ package io.xpipe.app.fxcomps.impl;
import atlantafx.base.controls.Popover; import atlantafx.base.controls.Popover;
import atlantafx.base.theme.Styles; import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.storage.store.*; import io.xpipe.app.comp.store.*;
import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.DataStoreProviders; import io.xpipe.app.ext.DataStoreProviders;
@ -106,7 +106,7 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
comp.disable(new SimpleBooleanProperty(true)); comp.disable(new SimpleBooleanProperty(true));
} }
}); });
var category = new DataStoreCategoryChoiceComp(selectedCategory).styleClass(Styles.LEFT_PILL); var category = new DataStoreCategoryChoiceComp(initialCategory != null ? initialCategory.getRoot() : null, selectedCategory).styleClass(Styles.LEFT_PILL);
var filter = new FilterComp(filterText) var filter = new FilterComp(filterText)
.styleClass(Styles.CENTER_PILL) .styleClass(Styles.CENTER_PILL)
.hgrow() .hgrow()

View file

@ -1,7 +1,7 @@
package io.xpipe.app.fxcomps.impl; package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.comp.storage.store.StoreCategoryWrapper; import io.xpipe.app.comp.store.StoreCategoryWrapper;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.app.storage.DataStoreEntryRef;

View file

@ -3,8 +3,8 @@ package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.comp.base.CountComp; import io.xpipe.app.comp.base.CountComp;
import io.xpipe.app.comp.base.LazyTextFieldComp; import io.xpipe.app.comp.base.LazyTextFieldComp;
import io.xpipe.app.comp.base.ListBoxViewComp; import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.comp.storage.store.StoreCategoryWrapper; import io.xpipe.app.comp.store.StoreCategoryWrapper;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;

View file

@ -1,6 +1,6 @@
package io.xpipe.app.fxcomps.impl; package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.comp.storage.store.StoreCategoryWrapper; import io.xpipe.app.comp.store.StoreCategoryWrapper;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;

View file

@ -37,8 +37,10 @@ public abstract class DataStorage {
private static DataStorage INSTANCE; private static DataStorage INSTANCE;
protected final Path dir; protected final Path dir;
@Getter @Getter
protected final List<DataStoreCategory> storeCategories; protected final List<DataStoreCategory> storeCategories;
@Getter @Getter
protected final Set<DataStoreEntry> storeEntries; protected final Set<DataStoreEntry> storeEntries;
@ -59,10 +61,14 @@ public abstract class DataStorage {
return getStoreCategoryIfPresent(DEFAULT_CATEGORY_UUID).orElseThrow(); return getStoreCategoryIfPresent(DEFAULT_CATEGORY_UUID).orElseThrow();
} }
public DataStoreCategory getAllCategory() { public DataStoreCategory getAllConnectionsCategory() {
return getStoreCategoryIfPresent(ALL_CONNECTIONS_CATEGORY_UUID).orElseThrow(); return getStoreCategoryIfPresent(ALL_CONNECTIONS_CATEGORY_UUID).orElseThrow();
} }
public DataStoreCategory getAllScriptsCategory() {
return getStoreCategoryIfPresent(ALL_SCRIPTS_CATEGORY_UUID).orElseThrow();
}
private static boolean shouldPersist() { private static boolean shouldPersist() {
if (System.getProperty(PERSIST_PROP) != null) { if (System.getProperty(PERSIST_PROP) != null) {
return Boolean.parseBoolean(System.getProperty(PERSIST_PROP)); return Boolean.parseBoolean(System.getProperty(PERSIST_PROP));
@ -195,7 +201,7 @@ public abstract class DataStorage {
} }
var oldChildren = getStoreEntries().stream() var oldChildren = getStoreEntries().stream()
.filter(other -> e.equals(other.getProvider().getLogicalParent(other))) .filter(other -> e.equals(other.getProvider().getDisplayParent(other)))
.toList(); .toList();
var toRemove = oldChildren.stream() var toRemove = oldChildren.stream()
.filter(entry -> newChildren.stream() .filter(entry -> newChildren.stream()
@ -258,7 +264,6 @@ public abstract class DataStorage {
saveAsync(); saveAsync();
} }
public DataStoreCategory addStoreCategoryIfNotPresent(@NonNull DataStoreCategory cat) { public DataStoreCategory addStoreCategoryIfNotPresent(@NonNull DataStoreCategory cat) {
if (storeCategories.contains(cat)) { if (storeCategories.contains(cat)) {
return cat; return cat;
@ -388,7 +393,23 @@ public abstract class DataStorage {
.getDisplayParent(entry) .getDisplayParent(entry)
.map(p -> !p.getCategoryUuid().equals(entry.getCategoryUuid())) .map(p -> !p.getCategoryUuid().equals(entry.getCategoryUuid()))
.orElse(false); .orElse(false);
return noParent || diffParentCategory; var loop = isParentLoop(entry);
return noParent || diffParentCategory || loop;
}
private boolean isParentLoop(DataStoreEntry entry) {
var es = new HashSet<DataStoreEntry>();
DataStoreEntry current = entry;
while ((current = getDisplayParent(current).orElse(null)) != null) {
if (es.contains(current)) {
return true;
}
es.add(current);
}
return false;
} }
public DataStoreEntry getRootForEntry(DataStoreEntry entry) { public DataStoreEntry getRootForEntry(DataStoreEntry entry) {
@ -469,7 +490,7 @@ public abstract class DataStorage {
} }
var parent = getDisplayParent(other); var parent = getDisplayParent(other);
return parent.isPresent() && parent.get().equals(entry); return parent.isPresent() && parent.get().equals(entry) && !isParentLoop(entry);
}) })
.collect(Collectors.toSet()); .collect(Collectors.toSet());
entry.setChildrenCache(children); entry.setChildrenCache(children);
@ -483,20 +504,26 @@ public abstract class DataStorage {
.toList()); .toList());
} }
public DataStoreId getId(DataStoreEntry entry) { private List<DataStoreEntry> getHierarchy(DataStoreEntry entry) {
var names = new ArrayList<String>(); var es = new ArrayList<DataStoreEntry>();
names.add(entry.getName().replaceAll(":", "_"));
DataStoreEntry current = entry; DataStoreEntry current = entry;
while ((current = getDisplayParent(current).orElse(null)) != null) { while ((current = getDisplayParent(current).orElse(null)) != null) {
if (new LocalStore().equals(current.getStore())) { if (es.contains(current)) {
break; break;
} }
names.add(0, current.getName().replaceAll(":", "_")); es.add(0, current);
} }
return DataStoreId.create(names.toArray(String[]::new)); return es;
}
public DataStoreId getId(DataStoreEntry entry) {
return DataStoreId.create(getHierarchy(entry).stream()
.filter(e -> !(e.getStore() instanceof LocalStore))
.map(e -> e.getName().replaceAll(":", "_"))
.toArray(String[]::new));
} }
public Optional<DataStoreEntry> getStoreEntryIfPresent(@NonNull DataStoreId id) { public Optional<DataStoreEntry> getStoreEntryIfPresent(@NonNull DataStoreId id) {
@ -602,5 +629,4 @@ public abstract class DataStorage {
public DataStoreEntry local() { public DataStoreEntry local() {
return getStoreEntryIfPresent(LOCAL_ID).orElse(null); return getStoreEntryIfPresent(LOCAL_ID).orElse(null);
} }
} }

View file

@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import io.xpipe.app.comp.storage.store.StoreSortMode; import io.xpipe.app.comp.store.StoreSortMode;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NonNull; import lombok.NonNull;

View file

@ -1,6 +1,6 @@
package io.xpipe.app.storage; package io.xpipe.app.storage;
import io.xpipe.app.comp.storage.store.StoreSortMode; import io.xpipe.app.comp.store.StoreSortMode;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.prefs.AppPrefs;

View file

@ -1,9 +1,10 @@
package io.xpipe.app.util; package io.xpipe.app.util;
import io.xpipe.app.comp.storage.store.StoreCategoryWrapper; import io.xpipe.app.comp.store.StoreCategoryWrapper;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.util.PlatformThread; import io.xpipe.app.fxcomps.util.PlatformThread;
import io.xpipe.app.storage.DataStoreCategory;
import javafx.beans.property.Property; import javafx.beans.property.Property;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
@ -14,15 +15,17 @@ import lombok.Value;
public class DataStoreCategoryChoiceComp extends SimpleComp { public class DataStoreCategoryChoiceComp extends SimpleComp {
private final DataStoreCategory root;
private final Property<StoreCategoryWrapper> selected; private final Property<StoreCategoryWrapper> selected;
public DataStoreCategoryChoiceComp(Property<StoreCategoryWrapper> selected) { public DataStoreCategoryChoiceComp(DataStoreCategory root, Property<StoreCategoryWrapper> selected) {
this.root = root;
this.selected = selected; this.selected = selected;
} }
@Override @Override
protected Region createSimple() { protected Region createSimple() {
var box = new ComboBox<>(StoreViewState.get().getSortedCategories()); var box = new ComboBox<>(StoreViewState.get().getSortedCategories(root));
box.setValue(selected.getValue()); box.setValue(selected.getValue());
box.valueProperty().addListener((observable, oldValue, newValue) -> { box.valueProperty().addListener((observable, oldValue, newValue) -> {
selected.setValue(newValue); selected.setValue(newValue);

View file

@ -1,6 +1,6 @@
package io.xpipe.app.util; package io.xpipe.app.util;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntry;

View file

@ -2,7 +2,7 @@ package io.xpipe.app.util;
import io.xpipe.app.comp.base.ListSelectorComp; import io.xpipe.app.comp.base.ListSelectorComp;
import io.xpipe.app.comp.base.MultiStepComp; import io.xpipe.app.comp.base.MultiStepComp;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.AppI18n; import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppWindowHelper; import io.xpipe.app.core.AppWindowHelper;
import io.xpipe.app.ext.ScanProvider; import io.xpipe.app.ext.ScanProvider;

View file

@ -37,7 +37,6 @@ open module io.xpipe.app {
exports io.xpipe.app.browser.action; exports io.xpipe.app.browser.action;
exports io.xpipe.app.browser; exports io.xpipe.app.browser;
exports io.xpipe.app.browser.icon; exports io.xpipe.app.browser.icon;
exports io.xpipe.app.comp.storage.store;
requires com.sun.jna; requires com.sun.jna;
requires com.sun.jna.platform; requires com.sun.jna.platform;

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -30,9 +30,9 @@
.store-header-bar .menu-button { .store-header-bar .menu-button {
-fx-background-radius: 4px; -fx-background-radius: 4px;
-fx-border-width: 0.05em; -fx-border-radius: 4px;
-fx-border-radius: 4px; -fx-border-width: 1px;
-fx-padding: -1px; -fx-padding: 0;
-fx-background-color: -color-fg-default; -fx-background-color: -color-fg-default;
-fx-border-color: -color-bg-default; -fx-border-color: -color-bg-default;
} }

View file

@ -1,7 +1,7 @@
## Update procedure # Update procedure
Note that the automatic updater is broken in version 1.6.0. It will freeze the application and not perform the update. Note that the automatic updater is broken in version 1.6.0. It will freeze the application and not perform the update. **So do not try to click the install button**!
So you have to install it manually from https://github.com/xpipe-io/xpipe/releases/tag/1.7.0. You can easily do this as uninstalling the old version does not delete any user data. You have to install it manually from https://github.com/xpipe-io/xpipe/releases/tag/1.7.0. You can easily do this as uninstalling the old version does not delete any user data.
## Changes in 1.7.0 ## Changes in 1.7.0
@ -21,6 +21,11 @@ This merges the process of validating/refreshing with the process of establishin
It also enables a custom display and instant updates of the information displayed for a connection. It also enables a custom display and instant updates of the information displayed for a connection.
You will definitely notice this change when you connect to a system. You will definitely notice this change when you connect to a system.
### Performance improvements
The entire storage and UI handling of connections has been reworked to improve performance.
Especially if you're dealing with a large amount of connections, this will be noticeable.
### Colors ### Colors
You can now assign colors to connections for organizational purposes to help in situations when many connections are opened in the file browser and terminals at the same time. You can now assign colors to connections for organizational purposes to help in situations when many connections are opened in the file browser and terminals at the same time.
@ -28,6 +33,7 @@ These colors will be shown to identify tabs everywhere within XPipe and also out
### Other changes ### Other changes
- Codesign executables on Windows
- Fix application not starting up or exiting properly sometimes - Fix application not starting up or exiting properly sometimes
- Add support for bsd-based systems - Add support for bsd-based systems
- Fix OPNsense shells timing out - Fix OPNsense shells timing out

View file

@ -1,6 +1,6 @@
package io.xpipe.ext.base.action; package io.xpipe.ext.base.action;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.comp.store.GuiDsStoreCreator; import io.xpipe.app.comp.store.GuiDsStoreCreator;
import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStorage;
@ -30,7 +30,7 @@ public class XPipeUrlAction implements ActionProvider {
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
actionProvider.getDataStoreCallSite().createAction(entry.getStore().asNeeded()).execute(); actionProvider.getDataStoreCallSite().createAction(entry.ref()).execute();
} }
} }

View file

@ -3,10 +3,10 @@ package io.xpipe.ext.base.script;
import io.xpipe.app.comp.base.DropdownComp; import io.xpipe.app.comp.base.DropdownComp;
import io.xpipe.app.comp.base.StoreToggleComp; import io.xpipe.app.comp.base.StoreToggleComp;
import io.xpipe.app.comp.base.SystemStateComp; import io.xpipe.app.comp.base.SystemStateComp;
import io.xpipe.app.comp.storage.store.DenseStoreEntryComp; import io.xpipe.app.comp.store.DenseStoreEntryComp;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.comp.storage.store.StoreSection; import io.xpipe.app.comp.store.StoreSection;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.ext.DataStoreProvider; import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.GuiDialog; import io.xpipe.app.ext.GuiDialog;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
@ -51,9 +51,8 @@ public class ScriptGroupStoreProvider implements DataStoreProvider {
.description("scriptGroupDescription") .description("scriptGroupDescription")
.addComp( .addComp(
new DataStoreChoiceComp<>( new DataStoreChoiceComp<>(
DataStoreChoiceComp.Mode.OTHER, null, group, ScriptGroupStore.class, ref->! ref.getEntry().equals(entry), StoreViewState.get().getAllScriptsCategory()), DataStoreChoiceComp.Mode.OTHER, entry, group, ScriptGroupStore.class, null, StoreViewState.get().getAllScriptsCategory()),
group) group)
.nonNull()
.bind( .bind(
() -> { () -> {
return ScriptGroupStore.builder() return ScriptGroupStore.builder()
@ -65,6 +64,12 @@ public class ScriptGroupStoreProvider implements DataStoreProvider {
.buildDialog(); .buildDialog();
} }
@Override
public DataStoreEntry getDisplayParent(DataStoreEntry store) {
ScriptGroupStore scriptStore = store.getStore().asNeeded();
return scriptStore.getParent() != null ? scriptStore.getParent().get() : null;
}
@Override @Override
public DataStore defaultStore() { public DataStore defaultStore() {
return ScriptGroupStore.builder().build(); return ScriptGroupStore.builder().build();

View file

@ -29,7 +29,8 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore,
public static ShellControl controlWithScripts(ShellControl pc, List<DataStoreEntryRef<ScriptStore>> refs) { public static ShellControl controlWithScripts(ShellControl pc, List<DataStoreEntryRef<ScriptStore>> refs) {
pc.onInit(shellControl -> { pc.onInit(shellControl -> {
var scripts = flatten(refs).stream() var flattened = flatten(refs);
var scripts = flattened.stream()
.map(simpleScriptStore -> simpleScriptStore.prepareDumbScript(shellControl)) .map(simpleScriptStore -> simpleScriptStore.prepareDumbScript(shellControl))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
@ -37,7 +38,7 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore,
shellControl.executeSimpleBooleanCommand(scripts); shellControl.executeSimpleBooleanCommand(scripts);
} }
var terminalCommands = flatten(refs).stream() var terminalCommands = flattened.stream()
.map(simpleScriptStore -> simpleScriptStore.prepareTerminalScript(shellControl)) .map(simpleScriptStore -> simpleScriptStore.prepareTerminalScript(shellControl))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
@ -90,6 +91,11 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore,
if (scripts != null) { if (scripts != null) {
Validators.contentNonNull(scripts); Validators.contentNonNull(scripts);
} }
// Prevent possible stack overflow
// for (DataStoreEntryRef<ScriptStore> s : getEffectiveScripts()) {
// s.checkComplete();
// }
} }
public LinkedHashSet<SimpleScriptStore> getFlattenedScripts() { public LinkedHashSet<SimpleScriptStore> getFlattenedScripts() {

View file

@ -56,12 +56,12 @@ public class SimpleScriptStore extends ScriptStore {
} }
public void queryFlattenedScripts(LinkedHashSet<SimpleScriptStore> all) { public void queryFlattenedScripts(LinkedHashSet<SimpleScriptStore> all) {
all.add(this);
getEffectiveScripts().stream() getEffectiveScripts().stream()
.filter(scriptStoreDataStoreEntryRef -> !all.contains(scriptStoreDataStoreEntryRef.getStore())) .filter(scriptStoreDataStoreEntryRef -> !all.contains(scriptStoreDataStoreEntryRef.getStore()))
.forEach(scriptStoreDataStoreEntryRef -> { .forEach(scriptStoreDataStoreEntryRef -> {
scriptStoreDataStoreEntryRef.getStore().queryFlattenedScripts(all); scriptStoreDataStoreEntryRef.getStore().queryFlattenedScripts(all);
}); });
all.add(this);
} }
@Getter @Getter

View file

@ -4,10 +4,10 @@ import io.xpipe.app.comp.base.DropdownComp;
import io.xpipe.app.comp.base.IntegratedTextAreaComp; import io.xpipe.app.comp.base.IntegratedTextAreaComp;
import io.xpipe.app.comp.base.StoreToggleComp; import io.xpipe.app.comp.base.StoreToggleComp;
import io.xpipe.app.comp.base.SystemStateComp; import io.xpipe.app.comp.base.SystemStateComp;
import io.xpipe.app.comp.storage.store.DenseStoreEntryComp; import io.xpipe.app.comp.store.DenseStoreEntryComp;
import io.xpipe.app.comp.storage.store.StoreEntryWrapper; import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.comp.storage.store.StoreSection; import io.xpipe.app.comp.store.StoreSection;
import io.xpipe.app.comp.storage.store.StoreViewState; import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.AppExtensionManager; import io.xpipe.app.core.AppExtensionManager;
import io.xpipe.app.ext.DataStoreProvider; import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.GuiDialog; import io.xpipe.app.ext.GuiDialog;

View file

@ -1,6 +1,6 @@
dir=~/.xpipe/scriptdata/starship dir=~/.xpipe/scriptdata/starship
export PATH="$PATH:$dir" export PATH="$PATH:$dir"
which starship > /dev/null which starship > /dev/null 2>&1
if [ "$?" != 0 ]; then if [ "$?" != 0 ]; then
mkdir -p "$dir" && \ mkdir -p "$dir" && \
which curl > /dev/null && \ which curl > /dev/null && \

View file

@ -1,6 +1,6 @@
set dir ~/.xpipe/scriptdata/starship set dir ~/.xpipe/scriptdata/starship
export PATH="$PATH:$dir" export PATH="$PATH:$dir"
which starship > /dev/null which starship > /dev/null 2>&1
if [ $status != 0 ] if [ $status != 0 ]
mkdir -p "$dir" && \ mkdir -p "$dir" && \
which curl > /dev/null && \ which curl > /dev/null && \

View file

@ -1,6 +1,6 @@
dir=~/.xpipe/scriptdata/starship dir=~/.xpipe/scriptdata/starship
export PATH="$PATH:$dir" export PATH="$PATH:$dir"
which starship > /dev/null which starship > /dev/null 2>&1
if [ "$?" != 0 ]; then if [ "$?" != 0 ]; then
mkdir -p "$dir" && \ mkdir -p "$dir" && \
which curl > /dev/null && \ which curl > /dev/null && \