mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +00:00
More script rework, state rework, category fixes, and bug fixes
This commit is contained in:
parent
87d1d45cae
commit
43d7e0830c
33 changed files with 500 additions and 309 deletions
|
@ -10,9 +10,11 @@ import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
public class StoreToggleComp extends SimpleComp {
|
public class StoreToggleComp extends SimpleComp {
|
||||||
|
|
||||||
private final String nameKey;
|
private final String nameKey;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Optional;
|
||||||
@Getter
|
@Getter
|
||||||
public class StoreCategoryWrapper {
|
public class StoreCategoryWrapper {
|
||||||
|
|
||||||
|
private final DataStoreCategory root;
|
||||||
private final int depth;
|
private final int depth;
|
||||||
private final Property<String> name;
|
private final Property<String> name;
|
||||||
private final DataStoreCategory category;
|
private final DataStoreCategory category;
|
||||||
|
@ -30,15 +31,18 @@ public class StoreCategoryWrapper {
|
||||||
|
|
||||||
public StoreCategoryWrapper(DataStoreCategory category) {
|
public StoreCategoryWrapper(DataStoreCategory category) {
|
||||||
var d = 0;
|
var d = 0;
|
||||||
|
DataStoreCategory last = category;
|
||||||
DataStoreCategory p = category;
|
DataStoreCategory p = category;
|
||||||
while ((p = DataStorage.get()
|
while ((p = DataStorage.get()
|
||||||
.getStoreCategoryIfPresent(p.getParentCategory())
|
.getStoreCategoryIfPresent(p.getParentCategory())
|
||||||
.orElse(null))
|
.orElse(null))
|
||||||
!= null) {
|
!= null) {
|
||||||
d++;
|
d++;
|
||||||
|
last = p;
|
||||||
}
|
}
|
||||||
depth = d;
|
depth = d;
|
||||||
|
|
||||||
|
this.root = last;
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.name = new SimpleStringProperty();
|
this.name = new SimpleStringProperty();
|
||||||
this.lastAccess = new SimpleObjectProperty<>();
|
this.lastAccess = new SimpleObjectProperty<>();
|
||||||
|
|
|
@ -290,6 +290,16 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||||
contextMenu.getItems().add(item);
|
contextMenu.getItems().add(item);
|
||||||
|
|
||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
|
var run = new MenuItem(null, new FontIcon("mdi2c-code-greater-than"));
|
||||||
|
run.textProperty().bind(AppI18n.observable("base.execute"));
|
||||||
|
run.setOnAction(event -> {
|
||||||
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
|
p.getKey().getDataStoreCallSite().createAction(wrapper.getEntry().getStore().asNeeded()).execute();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
menu.getItems().add(run);
|
||||||
|
|
||||||
|
|
||||||
var sc = new MenuItem(null, new FontIcon("mdi2c-code-greater-than"));
|
var sc = new MenuItem(null, new FontIcon("mdi2c-code-greater-than"));
|
||||||
var url = "xpipe://action/" + p.getKey().getId() + "/"
|
var url = "xpipe://action/" + p.getKey().getId() + "/"
|
||||||
+ wrapper.getEntry().getUuid();
|
+ wrapper.getEntry().getUuid();
|
||||||
|
@ -329,15 +339,17 @@ public abstract class StoreEntryComp extends SimpleComp {
|
||||||
contextMenu.getItems().add(browse);
|
contextMenu.getItems().add(browse);
|
||||||
}
|
}
|
||||||
|
|
||||||
var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline"));
|
if (wrapper.getEntry().getProvider() != null && wrapper.getEntry().getProvider().canMoveCategories()) {
|
||||||
StoreViewState.get().getSortedCategories().forEach(storeCategoryWrapper -> {
|
var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline"));
|
||||||
MenuItem m = new MenuItem(storeCategoryWrapper.getName());
|
StoreViewState.get().getSortedCategories().forEach(storeCategoryWrapper -> {
|
||||||
m.setOnAction(event -> {
|
MenuItem m = new MenuItem(storeCategoryWrapper.getName());
|
||||||
wrapper.moveTo(storeCategoryWrapper.getCategory());
|
m.setOnAction(event -> {
|
||||||
|
wrapper.moveTo(storeCategoryWrapper.getCategory());
|
||||||
|
});
|
||||||
|
move.getItems().add(m);
|
||||||
});
|
});
|
||||||
move.getItems().add(m);
|
contextMenu.getItems().add(move);
|
||||||
});
|
}
|
||||||
contextMenu.getItems().add(move);
|
|
||||||
|
|
||||||
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
|
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
|
||||||
del.disableProperty().bind(wrapper.getDeletable().not());
|
del.disableProperty().bind(wrapper.getDeletable().not());
|
||||||
|
|
|
@ -7,7 +7,9 @@ import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||||
import io.xpipe.app.fxcomps.impl.FilterComp;
|
import io.xpipe.app.fxcomps.impl.FilterComp;
|
||||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
@ -21,17 +23,28 @@ import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
public class StoreEntryListSideComp extends SimpleComp {
|
public class StoreEntryListSideComp extends SimpleComp {
|
||||||
|
|
||||||
private Region createGroupListHeader() {
|
private Region createGroupListHeader() {
|
||||||
var label = new Label("Connections");
|
var label = new Label();
|
||||||
|
label.textProperty().bind(Bindings.createStringBinding(() -> {
|
||||||
|
return StoreViewState.get().getActiveCategory().getValue().getRoot().equals(StoreViewState.get().getAllConnectionsCategory().getCategory()) ? "Connections" : "Scripts";
|
||||||
|
}, StoreViewState.get().getActiveCategory()));
|
||||||
label.getStyleClass().add("name");
|
label.getStyleClass().add("name");
|
||||||
|
|
||||||
var shownList = BindingsHelper.filteredContentBinding(
|
var all = BindingsHelper.filteredContentBinding(
|
||||||
StoreViewState.get().getAllEntries(),
|
StoreViewState.get().getAllEntries(),
|
||||||
|
storeEntryWrapper -> {
|
||||||
|
var cat = DataStorage.get().getStoreCategoryIfPresent(storeEntryWrapper.getEntry().getCategoryUuid()).orElse(null);
|
||||||
|
var storeRoot = cat != null ? DataStorage.get().getRootCategory(cat) : null;
|
||||||
|
return StoreViewState.get().getActiveCategory().getValue().getRoot().equals(storeRoot);
|
||||||
|
},
|
||||||
|
StoreViewState.get().getActiveCategory());
|
||||||
|
var shownList = BindingsHelper.filteredContentBinding(
|
||||||
|
all,
|
||||||
storeEntryWrapper -> {
|
storeEntryWrapper -> {
|
||||||
return storeEntryWrapper.shouldShow(
|
return storeEntryWrapper.shouldShow(
|
||||||
StoreViewState.get().getFilterString().getValue());
|
StoreViewState.get().getFilterString().getValue());
|
||||||
},
|
},
|
||||||
StoreViewState.get().getFilterString());
|
StoreViewState.get().getFilterString());
|
||||||
var count = new CountComp<>(shownList, StoreViewState.get().getAllEntries());
|
var count = new CountComp<>(shownList, all);
|
||||||
|
|
||||||
var spacer = new Region();
|
var spacer = new Region();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import io.xpipe.app.util.ThreadHelper;
|
||||||
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.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
@ -34,8 +35,8 @@ public class StoreEntryWrapper {
|
||||||
private final Property<ActionProvider.DefaultDataStoreCallSite<?>> defaultActionProvider;
|
private final Property<ActionProvider.DefaultDataStoreCallSite<?>> defaultActionProvider;
|
||||||
private final BooleanProperty deletable = new SimpleBooleanProperty();
|
private final BooleanProperty deletable = new SimpleBooleanProperty();
|
||||||
private final BooleanProperty expanded = new SimpleBooleanProperty();
|
private final BooleanProperty expanded = new SimpleBooleanProperty();
|
||||||
private final Property<StoreCategoryWrapper> category = new SimpleObjectProperty<>();
|
|
||||||
private final Property<Object> persistentState = new SimpleObjectProperty<>();
|
private final Property<Object> persistentState = new SimpleObjectProperty<>();
|
||||||
|
private final MapProperty<String, Object> cache = new SimpleMapProperty<>(FXCollections.observableHashMap());
|
||||||
|
|
||||||
public StoreEntryWrapper(DataStoreEntry entry) {
|
public StoreEntryWrapper(DataStoreEntry entry) {
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
|
@ -144,6 +145,7 @@ public class StoreEntryWrapper {
|
||||||
expanded.setValue(entry.isExpanded());
|
expanded.setValue(entry.isExpanded());
|
||||||
observing.setValue(entry.isObserving());
|
observing.setValue(entry.isObserving());
|
||||||
persistentState.setValue(entry.getStorePersistentState());
|
persistentState.setValue(entry.getStorePersistentState());
|
||||||
|
cache.putAll(entry.getStoreCache());
|
||||||
|
|
||||||
inRefresh.setValue(entry.isInRefresh());
|
inRefresh.setValue(entry.isInRefresh());
|
||||||
deletable.setValue(entry.getConfiguration().isDeletable()
|
deletable.setValue(entry.getConfiguration().isDeletable()
|
||||||
|
|
|
@ -2,8 +2,8 @@ package io.xpipe.app.comp.storage.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;
|
||||||
|
import io.xpipe.app.fxcomps.impl.StoreCategoryListComp;
|
||||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||||
import io.xpipe.app.util.FeatureProvider;
|
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
@ -17,7 +17,7 @@ public class StoreSidebarComp extends SimpleComp {
|
||||||
var sideBar = new VerticalComp(List.of(
|
var sideBar = new VerticalComp(List.of(
|
||||||
new StoreEntryListSideComp(),
|
new StoreEntryListSideComp(),
|
||||||
new StoreSortComp(),
|
new StoreSortComp(),
|
||||||
FeatureProvider.get().organizationComp(),
|
new StoreCategoryListComp(),
|
||||||
Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar")));
|
Comp.of(() -> new Region()).styleClass("bar").styleClass("filler-bar")));
|
||||||
sideBar.apply(struc -> struc.get().setFillWidth(true));
|
sideBar.apply(struc -> struc.get().setFillWidth(true));
|
||||||
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(2), Priority.ALWAYS));
|
sideBar.apply(s -> VBox.setVgrow(s.get().getChildren().get(2), Priority.ALWAYS));
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class StoreViewState {
|
||||||
} 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().getAllCategory()));
|
||||||
activeCategory.setValue(getAllCategory());
|
activeCategory.setValue(getAllConnectionsCategory());
|
||||||
ErrorEvent.fromThrowable(exception).handle();
|
ErrorEvent.fromThrowable(exception).handle();
|
||||||
}
|
}
|
||||||
topLevelSection = tl;
|
topLevelSection = tl;
|
||||||
|
@ -58,6 +58,17 @@ public class StoreViewState {
|
||||||
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) {
|
||||||
|
var o1Root = o1.getRoot();
|
||||||
|
var o2Root = o2.getRoot();
|
||||||
|
|
||||||
|
if (o1Root.equals(getAllConnectionsCategory().getCategory()) && !o1Root.equals(o2Root)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o2Root.equals(getAllConnectionsCategory().getCategory()) && !o1Root.equals(o2Root)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (o1.getParent() == null && o2.getParent() == null) {
|
if (o1.getParent() == null && o2.getParent() == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -81,19 +92,18 @@ public class StoreViewState {
|
||||||
return categories.sorted(comparator);
|
return categories.sorted(comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StoreCategoryWrapper getAllCategory() {
|
public StoreCategoryWrapper getAllConnectionsCategory() {
|
||||||
return categories.stream()
|
return categories.stream()
|
||||||
.filter(storeCategoryWrapper ->
|
.filter(storeCategoryWrapper ->
|
||||||
storeCategoryWrapper.getCategory().getUuid().equals(DataStorage.ALL_CATEGORY_UUID))
|
storeCategoryWrapper.getCategory().getUuid().equals(DataStorage.ALL_CONNECTIONS_CATEGORY_UUID))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StoreCategoryWrapper getAllScriptsCategory() {
|
||||||
public StoreCategoryWrapper getScriptsCategory() {
|
|
||||||
return categories.stream()
|
return categories.stream()
|
||||||
.filter(storeCategoryWrapper ->
|
.filter(storeCategoryWrapper ->
|
||||||
storeCategoryWrapper.getCategory().getUuid().equals(DataStorage.SCRIPTS_CATEGORY_UUID))
|
storeCategoryWrapper.getCategory().getUuid().equals(DataStorage.ALL_SCRIPTS_CATEGORY_UUID))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,8 @@ 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, boolean staticDisplay
|
boolean exists,
|
||||||
) {
|
boolean staticDisplay) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
|
@ -115,7 +115,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
true, true);
|
true,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showCreation(DataStoreProvider selected, Predicate<DataStoreProvider> filter) {
|
public static void showCreation(DataStoreProvider selected, Predicate<DataStoreProvider> filter) {
|
||||||
|
@ -134,7 +135,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
ErrorEvent.fromThrowable(ex).handle();
|
ErrorEvent.fromThrowable(ex).handle();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
false, false);
|
false,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void show(
|
public static void show(
|
||||||
|
@ -155,8 +157,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
window -> {
|
window -> {
|
||||||
return new MultiStepComp() {
|
return new MultiStepComp() {
|
||||||
|
|
||||||
private final GuiDsStoreCreator creator =
|
private final GuiDsStoreCreator creator = new GuiDsStoreCreator(
|
||||||
new GuiDsStoreCreator(this, prop, store, filter, initialName, exists, staticDisplay);
|
this, prop, store, filter, initialName, exists, staticDisplay);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Entry> setup() {
|
protected List<Entry> setup() {
|
||||||
|
@ -227,7 +229,21 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DataStoreEntry.createNew(UUID.randomUUID(), DataStorage.get().getSelectedCategory().getUuid(), name.getValue(), store.getValue());
|
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)
|
entry)
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -22,6 +22,10 @@ import java.util.List;
|
||||||
|
|
||||||
public interface DataStoreProvider {
|
public interface DataStoreProvider {
|
||||||
|
|
||||||
|
default boolean canMoveCategories() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
default boolean alwaysShowSummary() {
|
default boolean alwaysShowSummary() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,31 +39,16 @@ import java.util.function.Predicate;
|
||||||
public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
||||||
|
|
||||||
public static <T extends DataStore> DataStoreChoiceComp<T> other(
|
public static <T extends DataStore> DataStoreChoiceComp<T> other(
|
||||||
Property<DataStoreEntryRef<T>> selected, Class<T> clazz, Predicate<DataStoreEntryRef<T>> filter) {
|
Property<DataStoreEntryRef<T>> selected, Class<T> clazz, Predicate<DataStoreEntryRef<T>> filter, StoreCategoryWrapper initialCategory) {
|
||||||
return new DataStoreChoiceComp<>(Mode.OTHER, null, selected, clazz, filter);
|
return new DataStoreChoiceComp<>(Mode.OTHER, null, selected, clazz, filter, initialCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataStoreChoiceComp<ShellStore> proxy(Property<DataStoreEntryRef<ShellStore>> selected) {
|
public static DataStoreChoiceComp<ShellStore> proxy(Property<DataStoreEntryRef<ShellStore>> selected, StoreCategoryWrapper initialCategory) {
|
||||||
return new DataStoreChoiceComp<>(Mode.PROXY, null, selected, ShellStore.class, null);
|
return new DataStoreChoiceComp<>(Mode.PROXY, null, selected, ShellStore.class, null, initialCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataStoreChoiceComp<ShellStore> host(Property<DataStoreEntryRef<ShellStore>> selected) {
|
public static DataStoreChoiceComp<ShellStore> host(Property<DataStoreEntryRef<ShellStore>> selected, StoreCategoryWrapper initialCategory) {
|
||||||
return new DataStoreChoiceComp<>(Mode.HOST, null, selected, ShellStore.class, null);
|
return new DataStoreChoiceComp<>(Mode.HOST, null, selected, ShellStore.class, null, initialCategory);
|
||||||
}
|
|
||||||
|
|
||||||
public static DataStoreChoiceComp<ShellStore> environment(
|
|
||||||
DataStoreEntry self, Property<DataStoreEntryRef<ShellStore>> selected) {
|
|
||||||
return new DataStoreChoiceComp<>(Mode.HOST, self, selected, ShellStore.class, shellStoreDataStoreEntryRef -> shellStoreDataStoreEntryRef.get().getProvider().canHaveSubShells());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DataStoreChoiceComp<ShellStore> proxy(
|
|
||||||
DataStoreEntry self, Property<DataStoreEntryRef<ShellStore>> selected) {
|
|
||||||
return new DataStoreChoiceComp<>(Mode.PROXY, self, selected, ShellStore.class, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DataStoreChoiceComp<ShellStore> host(
|
|
||||||
DataStoreEntry self, Property<DataStoreEntryRef<ShellStore>> selected) {
|
|
||||||
return new DataStoreChoiceComp<>(Mode.HOST, self, selected, ShellStore.class, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Mode {
|
public enum Mode {
|
||||||
|
@ -77,6 +62,7 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
||||||
private final Property<DataStoreEntryRef<T>> selected;
|
private final Property<DataStoreEntryRef<T>> selected;
|
||||||
private final Class<T> storeClass;
|
private final Class<T> storeClass;
|
||||||
private final Predicate<DataStoreEntryRef<T>> applicableCheck;
|
private final Predicate<DataStoreEntryRef<T>> applicableCheck;
|
||||||
|
private final StoreCategoryWrapper initialCategory;
|
||||||
|
|
||||||
private Popover popover;
|
private Popover popover;
|
||||||
|
|
||||||
|
@ -84,8 +70,9 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
||||||
// Rebuild popover if we have a non-null condition to allow for the content to be updated in case the condition
|
// Rebuild popover if we have a non-null condition to allow for the content to be updated in case the condition
|
||||||
// changed
|
// changed
|
||||||
if (popover == null || applicableCheck != null) {
|
if (popover == null || applicableCheck != null) {
|
||||||
|
var cur = StoreViewState.get().getActiveCategory().getValue();
|
||||||
var selectedCategory = new SimpleObjectProperty<>(
|
var selectedCategory = new SimpleObjectProperty<>(
|
||||||
StoreViewState.get().getActiveCategory().getValue());
|
initialCategory != null ? (initialCategory.getRoot().equals(cur.getRoot()) ? cur : initialCategory) : cur);
|
||||||
var filterText = new SimpleStringProperty();
|
var filterText = new SimpleStringProperty();
|
||||||
popover = new Popover();
|
popover = new Popover();
|
||||||
Predicate<StoreEntryWrapper> applicable = storeEntryWrapper -> {
|
Predicate<StoreEntryWrapper> applicable = storeEntryWrapper -> {
|
||||||
|
|
|
@ -1,6 +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.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;
|
||||||
|
@ -19,11 +20,15 @@ public class DataStoreListChoiceComp<T extends DataStore> extends SimpleComp {
|
||||||
private final ListProperty<DataStoreEntryRef<T>> selectedList;
|
private final ListProperty<DataStoreEntryRef<T>> selectedList;
|
||||||
private final Class<T> storeClass;
|
private final Class<T> storeClass;
|
||||||
private final Predicate<DataStoreEntryRef<T>> applicableCheck;
|
private final Predicate<DataStoreEntryRef<T>> applicableCheck;
|
||||||
|
private final StoreCategoryWrapper initialCategory;
|
||||||
|
|
||||||
public DataStoreListChoiceComp(ListProperty<DataStoreEntryRef<T>> selectedList, Class<T> storeClass, Predicate<DataStoreEntryRef<T>> applicableCheck) {
|
public DataStoreListChoiceComp(ListProperty<DataStoreEntryRef<T>> selectedList, Class<T> storeClass, Predicate<DataStoreEntryRef<T>> applicableCheck,
|
||||||
|
StoreCategoryWrapper initialCategory
|
||||||
|
) {
|
||||||
this.selectedList = selectedList;
|
this.selectedList = selectedList;
|
||||||
this.storeClass = storeClass;
|
this.storeClass = storeClass;
|
||||||
this.applicableCheck = applicableCheck;
|
this.applicableCheck = applicableCheck;
|
||||||
|
this.initialCategory = initialCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,7 +47,7 @@ public class DataStoreListChoiceComp<T extends DataStore> extends SimpleComp {
|
||||||
return hbox;
|
return hbox;
|
||||||
}).padding(new Insets(0)).apply(struc -> struc.get().setMinHeight(0)).apply(struc -> ((VBox) struc.get().getContent()).setSpacing(5));
|
}).padding(new Insets(0)).apply(struc -> struc.get().setMinHeight(0)).apply(struc -> ((VBox) struc.get().getContent()).setSpacing(5));
|
||||||
var selected = new SimpleObjectProperty<DataStoreEntryRef<T>>();
|
var selected = new SimpleObjectProperty<DataStoreEntryRef<T>>();
|
||||||
var add = new DataStoreChoiceComp<T>(DataStoreChoiceComp.Mode.OTHER, null, selected, storeClass, applicableCheck);
|
var add = new DataStoreChoiceComp<T>(DataStoreChoiceComp.Mode.OTHER, null, selected, storeClass, applicableCheck, initialCategory);
|
||||||
selected.addListener((observable, oldValue, newValue) -> {
|
selected.addListener((observable, oldValue, newValue) -> {
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
if (!selectedList.contains(newValue)
|
if (!selectedList.contains(newValue)
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
package io.xpipe.app.fxcomps.impl;
|
||||||
|
|
||||||
|
import io.xpipe.app.comp.base.CountComp;
|
||||||
|
import io.xpipe.app.comp.base.LazyTextFieldComp;
|
||||||
|
import io.xpipe.app.comp.base.ListBoxViewComp;
|
||||||
|
import io.xpipe.app.comp.storage.store.StoreCategoryWrapper;
|
||||||
|
import io.xpipe.app.comp.storage.store.StoreViewState;
|
||||||
|
import io.xpipe.app.core.AppFont;
|
||||||
|
import io.xpipe.app.core.AppI18n;
|
||||||
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
|
import io.xpipe.app.fxcomps.augment.ContextMenuAugment;
|
||||||
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
|
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||||
|
import io.xpipe.app.storage.DataStorage;
|
||||||
|
import io.xpipe.app.storage.DataStoreCategory;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.css.PseudoClass;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.ContextMenu;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
|
import javafx.scene.input.MouseButton;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Value;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Value
|
||||||
|
public class StoreCategoryComp extends SimpleComp {
|
||||||
|
|
||||||
|
private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected");
|
||||||
|
|
||||||
|
StoreCategoryWrapper category;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var i = Bindings.createStringBinding(
|
||||||
|
() -> {
|
||||||
|
if (!DataStorage.get().supportsSharing()) {
|
||||||
|
return "mdal-keyboard_arrow_right";
|
||||||
|
}
|
||||||
|
|
||||||
|
return category.getShare().getValue() ?
|
||||||
|
"mdi2a-account-convert" : "mdi2a-account-cancel";
|
||||||
|
},
|
||||||
|
category.getShare());
|
||||||
|
var icon = new IconButtonComp(i).apply(struc -> AppFont.small(struc.get())).apply(struc -> {
|
||||||
|
struc.get().setAlignment(Pos.CENTER);
|
||||||
|
struc.get().setPadding(new Insets(0, 0, 6, 0));
|
||||||
|
});
|
||||||
|
var name = new LazyTextFieldComp(category.nameProperty())
|
||||||
|
.apply(struc -> {
|
||||||
|
struc.get().prefWidthProperty().unbind();
|
||||||
|
struc.get().setPrefWidth(100);
|
||||||
|
struc.getTextField().minWidthProperty().bind(struc.get().widthProperty());
|
||||||
|
})
|
||||||
|
.styleClass("name")
|
||||||
|
.createRegion();
|
||||||
|
var showing = new SimpleBooleanProperty();
|
||||||
|
var settings = new IconButtonComp("mdomz-settings")
|
||||||
|
.styleClass("settings")
|
||||||
|
.apply(new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, () -> {
|
||||||
|
var cm = createContextMenu(name);
|
||||||
|
showing.bind(cm.showingProperty());
|
||||||
|
return cm;
|
||||||
|
}));
|
||||||
|
var shownList = BindingsHelper.filteredContentBinding(
|
||||||
|
category.getContainedEntries(),
|
||||||
|
storeEntryWrapper -> {
|
||||||
|
return storeEntryWrapper.shouldShow(
|
||||||
|
StoreViewState.get().getFilterString().getValue());
|
||||||
|
},
|
||||||
|
StoreViewState.get().getFilterString());
|
||||||
|
var count = new CountComp<>(shownList, category.getContainedEntries(), string -> "(" + string + ")");
|
||||||
|
var hover = new SimpleBooleanProperty();
|
||||||
|
var h = new HorizontalComp(List.of(
|
||||||
|
icon,
|
||||||
|
Comp.hspacer(4),
|
||||||
|
Comp.of(() -> name),
|
||||||
|
Comp.hspacer(),
|
||||||
|
count.hide(BindingsHelper.persist(hover.or(showing))),
|
||||||
|
settings.hide(BindingsHelper.persist(hover.not().and(showing.not())))));
|
||||||
|
h.apply(struc -> hover.bind(struc.get().hoverProperty()));
|
||||||
|
h.apply(struc -> struc.get().setOnMouseClicked(event -> {
|
||||||
|
category.select();
|
||||||
|
event.consume();
|
||||||
|
}));
|
||||||
|
h.apply(new ContextMenuAugment<>(
|
||||||
|
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY, () -> createContextMenu(name)));
|
||||||
|
h.padding(new Insets(0, 10, 0, (category.getDepth() * 8)));
|
||||||
|
h.styleClass("category-button");
|
||||||
|
var l = category.getChildren()
|
||||||
|
.sorted(Comparator.comparing(
|
||||||
|
storeCategoryWrapper -> storeCategoryWrapper.getName().toLowerCase(Locale.ROOT)));
|
||||||
|
var children = new ListBoxViewComp<>(l, l, storeCategoryWrapper -> new StoreCategoryComp(storeCategoryWrapper));
|
||||||
|
|
||||||
|
var emptyBinding = Bindings.isEmpty(category.getChildren());
|
||||||
|
var v = new VerticalComp(List.of(h, Comp.separator().hide(emptyBinding), children.hide(emptyBinding)));
|
||||||
|
v.styleClass("category");
|
||||||
|
v.apply(struc -> {
|
||||||
|
SimpleChangeListener.apply(StoreViewState.get().getActiveCategory(), val -> {
|
||||||
|
struc.get().pseudoClassStateChanged(SELECTED, val.equals(category));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return v.createRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContextMenu createContextMenu(Region text) {
|
||||||
|
var contextMenu = new ContextMenu();
|
||||||
|
AppFont.normal(contextMenu.getStyleableNode());
|
||||||
|
|
||||||
|
var newCategory = new MenuItem(AppI18n.get("newCategory"), new FontIcon("mdi2p-plus-thick"));
|
||||||
|
newCategory.setOnAction(event -> {
|
||||||
|
DataStorage.get()
|
||||||
|
.addStoreCategory(
|
||||||
|
DataStoreCategory.createNew(category.getCategory().getUuid(), "New category"));
|
||||||
|
});
|
||||||
|
contextMenu.getItems().add(newCategory);
|
||||||
|
|
||||||
|
var share = new MenuItem();
|
||||||
|
share.textProperty().bind(Bindings.createStringBinding(() -> {
|
||||||
|
if (category.getShare().getValue()) {
|
||||||
|
return AppI18n.get("unshare");
|
||||||
|
} else {
|
||||||
|
return AppI18n.get("share");
|
||||||
|
}
|
||||||
|
},category.getShare()));
|
||||||
|
share.graphicProperty().bind(Bindings.createObjectBinding(() -> {
|
||||||
|
if (category.getShare().getValue()) {
|
||||||
|
return new FontIcon("mdi2b-block-helper");
|
||||||
|
} else {
|
||||||
|
return new FontIcon("mdi2s-share");
|
||||||
|
}
|
||||||
|
},category.getShare()));
|
||||||
|
share.setOnAction(event -> {
|
||||||
|
category.getShare().setValue(!category.getShare().getValue());
|
||||||
|
});
|
||||||
|
contextMenu.getItems().add(share);
|
||||||
|
|
||||||
|
var refresh = new MenuItem(AppI18n.get("rename"), new FontIcon("mdal-360"));
|
||||||
|
refresh.setOnAction(event -> {
|
||||||
|
text.requestFocus();
|
||||||
|
});
|
||||||
|
contextMenu.getItems().add(refresh);
|
||||||
|
|
||||||
|
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
|
||||||
|
del.setOnAction(event -> {
|
||||||
|
category.delete();
|
||||||
|
});
|
||||||
|
contextMenu.getItems().add(del);
|
||||||
|
|
||||||
|
return contextMenu;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package io.xpipe.app.fxcomps.impl;
|
||||||
|
|
||||||
|
import io.xpipe.app.comp.storage.store.StoreViewState;
|
||||||
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
|
import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class StoreCategoryListComp extends SimpleComp {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var all = StoreViewState.get().getAllConnectionsCategory();
|
||||||
|
var scripts = StoreViewState.get().getAllScriptsCategory();
|
||||||
|
return new VerticalComp(List.of(
|
||||||
|
new StoreCategoryComp(all),
|
||||||
|
Comp.vspacer(10),
|
||||||
|
new StoreCategoryComp(scripts)))
|
||||||
|
.apply(struc -> struc.get().setFillWidth(true))
|
||||||
|
.apply(struc -> struc.get().setSpacing(3))
|
||||||
|
.styleClass("store-category-bar")
|
||||||
|
.createRegion();
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,7 +59,7 @@ public class DataStateProviderImpl extends DataStateProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var old = entry.get().getStoreCache().put(key, value);
|
entry.get().setStoreCache(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,8 +73,12 @@ public class DataStateProviderImpl extends DataStateProvider {
|
||||||
return def.get();
|
return def.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = entry.get().getStoreCache().computeIfAbsent(key, k -> def.get());
|
var r = entry.get().getStoreCache().get(key);
|
||||||
return c.cast(result);
|
if (r == null) {
|
||||||
|
r = def .get();
|
||||||
|
entry.get().setStoreCache(key, r);
|
||||||
|
}
|
||||||
|
return c.cast(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInStorage(DataStore store) {
|
public boolean isInStorage(DataStore store) {
|
||||||
|
|
|
@ -23,8 +23,8 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
public abstract class DataStorage {
|
public abstract class DataStorage {
|
||||||
|
|
||||||
public static final UUID ALL_CATEGORY_UUID = UUID.fromString("bfb0b51a-e7a3-4ce4-8878-8d4cb5828d6c");
|
public static final UUID ALL_CONNECTIONS_CATEGORY_UUID = UUID.fromString("bfb0b51a-e7a3-4ce4-8878-8d4cb5828d6c");
|
||||||
public static final UUID SCRIPTS_CATEGORY_UUID = UUID.fromString("19024cf9-d192-41a9-88a6-a22694cf716a");
|
public static final UUID ALL_SCRIPTS_CATEGORY_UUID = UUID.fromString("19024cf9-d192-41a9-88a6-a22694cf716a");
|
||||||
public static final UUID PREDEFINED_SCRIPTS_CATEGORY_UUID = UUID.fromString("5faf1d71-0efc-4293-8b70-299406396973");
|
public static final UUID PREDEFINED_SCRIPTS_CATEGORY_UUID = UUID.fromString("5faf1d71-0efc-4293-8b70-299406396973");
|
||||||
public static final UUID CUSTOM_SCRIPTS_CATEGORY_UUID = UUID.fromString("d3496db5-b709-41f9-abc0-ee0a660fbab9");
|
public static final UUID CUSTOM_SCRIPTS_CATEGORY_UUID = UUID.fromString("d3496db5-b709-41f9-abc0-ee0a660fbab9");
|
||||||
public static final UUID DEFAULT_CATEGORY_UUID = UUID.fromString("97458c07-75c0-4f9d-a06e-92d8cdf67c40");
|
public static final UUID DEFAULT_CATEGORY_UUID = UUID.fromString("97458c07-75c0-4f9d-a06e-92d8cdf67c40");
|
||||||
|
@ -68,7 +68,7 @@ public abstract class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataStoreCategory getAllCategory() {
|
public DataStoreCategory getAllCategory() {
|
||||||
return getStoreCategoryIfPresent(ALL_CATEGORY_UUID).orElseThrow();
|
return getStoreCategoryIfPresent(ALL_CONNECTIONS_CATEGORY_UUID).orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldPersist() {
|
private static boolean shouldPersist() {
|
||||||
|
@ -370,6 +370,17 @@ public abstract class DataStorage {
|
||||||
|
|
||||||
public abstract boolean supportsSharing();
|
public abstract boolean supportsSharing();
|
||||||
|
|
||||||
|
public DataStoreCategory getRootCategory(DataStoreCategory category) {
|
||||||
|
DataStoreCategory last = category;
|
||||||
|
DataStoreCategory p = category;
|
||||||
|
while ((p = DataStorage.get()
|
||||||
|
.getStoreCategoryIfPresent(p.getParentCategory())
|
||||||
|
.orElse(null))
|
||||||
|
!= null) {
|
||||||
|
last = p;
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<DataStoreCategory> getStoreCategoryIfPresent(UUID uuid) {
|
public Optional<DataStoreCategory> getStoreCategoryIfPresent(UUID uuid) {
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
|
@ -565,7 +576,7 @@ public abstract class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteStoreCategory(@NonNull DataStoreCategory cat) {
|
public void deleteStoreCategory(@NonNull DataStoreCategory cat) {
|
||||||
if (cat.getUuid().equals(DEFAULT_CATEGORY_UUID) || cat.getUuid().equals(ALL_CATEGORY_UUID)) {
|
if (cat.getUuid().equals(DEFAULT_CATEGORY_UUID) || cat.getUuid().equals(ALL_CONNECTIONS_CATEGORY_UUID)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,12 @@ public class DataStoreEntry extends StorageElement {
|
||||||
return new DataStoreEntryRef<T>(this);
|
return new DataStoreEntryRef<T>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStoreCache(String key, Object value) {
|
||||||
|
if (!Objects.equals(storeCache.put(key, value), value)) {
|
||||||
|
notifyUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setStorePersistentState(Object value) {
|
public void setStorePersistentState(Object value) {
|
||||||
var changed = !Objects.equals(storePersistentState, value);
|
var changed = !Objects.equals(storePersistentState, value);
|
||||||
this.storePersistentState = value;
|
this.storePersistentState = value;
|
||||||
|
|
|
@ -150,20 +150,20 @@ public class StandardStorage extends DataStorage {
|
||||||
ErrorEvent.fromThrowable(exception.get()).handle();
|
ErrorEvent.fromThrowable(exception.get()).handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getStoreCategoryIfPresent(ALL_CATEGORY_UUID).isEmpty()) {
|
if (getStoreCategoryIfPresent(ALL_CONNECTIONS_CATEGORY_UUID).isEmpty()) {
|
||||||
var cat = DataStoreCategory.createNew(null, ALL_CATEGORY_UUID,"All connections");
|
var cat = DataStoreCategory.createNew(null, ALL_CONNECTIONS_CATEGORY_UUID, "All connections");
|
||||||
cat.setDirectory(categoriesDir.resolve(ALL_CATEGORY_UUID.toString()));
|
cat.setDirectory(categoriesDir.resolve(ALL_CONNECTIONS_CATEGORY_UUID.toString()));
|
||||||
storeCategories.add(cat);
|
storeCategories.add(cat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getStoreCategoryIfPresent(SCRIPTS_CATEGORY_UUID).isEmpty()) {
|
if (getStoreCategoryIfPresent(ALL_SCRIPTS_CATEGORY_UUID).isEmpty()) {
|
||||||
var cat = DataStoreCategory.createNew(null, SCRIPTS_CATEGORY_UUID,"All scripts");
|
var cat = DataStoreCategory.createNew(null, ALL_SCRIPTS_CATEGORY_UUID, "All scripts");
|
||||||
cat.setDirectory(categoriesDir.resolve(SCRIPTS_CATEGORY_UUID.toString()));
|
cat.setDirectory(categoriesDir.resolve(ALL_SCRIPTS_CATEGORY_UUID.toString()));
|
||||||
storeCategories.add(cat);
|
storeCategories.add(cat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getStoreCategoryIfPresent(PREDEFINED_SCRIPTS_CATEGORY_UUID).isEmpty()) {
|
if (getStoreCategoryIfPresent(PREDEFINED_SCRIPTS_CATEGORY_UUID).isEmpty()) {
|
||||||
var cat = DataStoreCategory.createNew(SCRIPTS_CATEGORY_UUID, PREDEFINED_SCRIPTS_CATEGORY_UUID,"Predefined");
|
var cat = DataStoreCategory.createNew(ALL_SCRIPTS_CATEGORY_UUID, PREDEFINED_SCRIPTS_CATEGORY_UUID, "Predefined");
|
||||||
cat.setDirectory(categoriesDir.resolve(PREDEFINED_SCRIPTS_CATEGORY_UUID.toString()));
|
cat.setDirectory(categoriesDir.resolve(PREDEFINED_SCRIPTS_CATEGORY_UUID.toString()));
|
||||||
storeCategories.add(cat);
|
storeCategories.add(cat);
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ public class StandardStorage extends DataStorage {
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
Instant.now(),
|
Instant.now(),
|
||||||
true,
|
true,
|
||||||
ALL_CATEGORY_UUID,
|
ALL_CONNECTIONS_CATEGORY_UUID,
|
||||||
StoreSortMode.ALPHABETICAL_ASC, false
|
StoreSortMode.ALPHABETICAL_ASC, false
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -187,9 +187,10 @@ public class StandardStorage extends DataStorage {
|
||||||
if (dataStoreCategory.getParentCategory() != null
|
if (dataStoreCategory.getParentCategory() != null
|
||||||
&& getStoreCategoryIfPresent(dataStoreCategory.getParentCategory())
|
&& getStoreCategoryIfPresent(dataStoreCategory.getParentCategory())
|
||||||
.isEmpty()) {
|
.isEmpty()) {
|
||||||
dataStoreCategory.setParentCategory(ALL_CATEGORY_UUID);
|
dataStoreCategory.setParentCategory(ALL_CONNECTIONS_CATEGORY_UUID);
|
||||||
} else if (dataStoreCategory.getParentCategory() == null && !dataStoreCategory.getUuid().equals(ALL_CATEGORY_UUID) && !dataStoreCategory.getUuid().equals(SCRIPTS_CATEGORY_UUID)) {
|
} else if (dataStoreCategory.getParentCategory() == null && !dataStoreCategory.getUuid().equals(ALL_CONNECTIONS_CATEGORY_UUID) && !dataStoreCategory.getUuid().equals(
|
||||||
dataStoreCategory.setParentCategory(ALL_CATEGORY_UUID);
|
ALL_SCRIPTS_CATEGORY_UUID)) {
|
||||||
|
dataStoreCategory.setParentCategory(ALL_CONNECTIONS_CATEGORY_UUID);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class DataStoreCategoryChoiceComp extends SimpleComp {
|
||||||
textProperty().unbind();
|
textProperty().unbind();
|
||||||
if (w != null) {
|
if (w != null) {
|
||||||
textProperty().bind(w.nameProperty());
|
textProperty().bind(w.nameProperty());
|
||||||
setPadding(new Insets(6, 6, 6, 8 + (indent ? w.getDepth() * 6 : 0)));
|
setPadding(new Insets(6, 6, 6, 8 + (indent ? w.getDepth() * 8 : 0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,6 @@ public abstract class FeatureProvider {
|
||||||
|
|
||||||
public abstract void init();
|
public abstract void init();
|
||||||
|
|
||||||
public abstract Comp<?> organizationComp();
|
|
||||||
|
|
||||||
public abstract Comp<?> overviewPage();
|
public abstract Comp<?> overviewPage();
|
||||||
|
|
||||||
public abstract GitStorageHandler createStorageHandler();
|
public abstract GitStorageHandler createStorageHandler();
|
||||||
|
|
|
@ -2,6 +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.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;
|
||||||
|
@ -83,11 +84,12 @@ public class ScanAlert {
|
||||||
.name("scanAlertChoiceHeader")
|
.name("scanAlertChoiceHeader")
|
||||||
.description("scanAlertChoiceHeaderDescription")
|
.description("scanAlertChoiceHeaderDescription")
|
||||||
.addComp(new DataStoreChoiceComp<>(
|
.addComp(new DataStoreChoiceComp<>(
|
||||||
DataStoreChoiceComp.Mode.OTHER,
|
DataStoreChoiceComp.Mode.OTHER,
|
||||||
null,
|
null,
|
||||||
entry,
|
entry,
|
||||||
ShellStore.class,
|
ShellStore.class,
|
||||||
store1 -> true)
|
store1 -> true,
|
||||||
|
StoreViewState.get().getAllConnectionsCategory())
|
||||||
.disable(new SimpleBooleanProperty(initialStore != null)))
|
.disable(new SimpleBooleanProperty(initialStore != null)))
|
||||||
.name("scanAlertHeader")
|
.name("scanAlertHeader")
|
||||||
.description("scanAlertHeaderDescription")
|
.description("scanAlertHeaderDescription")
|
||||||
|
|
|
@ -112,7 +112,7 @@ reportOnGithubDescription=Open a new issue in the GitHub repository
|
||||||
reportErrorDescription=Send an error report with optional user feedback and diagnostics info
|
reportErrorDescription=Send an error report with optional user feedback and diagnostics info
|
||||||
ignoreError=Ignore error
|
ignoreError=Ignore error
|
||||||
ignoreErrorDescription=Ignore this error and continue like nothing happened
|
ignoreErrorDescription=Ignore this error and continue like nothing happened
|
||||||
provideEmail=Email address (optional, in case you want to get notified about fixes)
|
provideEmail=How to contact you (optional, only if you want to get notified about fixes)
|
||||||
additionalErrorInfo=Provide additional information (optional)
|
additionalErrorInfo=Provide additional information (optional)
|
||||||
additionalErrorAttachments=Select attachments (optional)
|
additionalErrorAttachments=Select attachments (optional)
|
||||||
dataHandlingPolicies=Privacy policy
|
dataHandlingPolicies=Privacy policy
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
.browser .bookmark-list *.scroll-bar:horizontal *.thumb,
|
.browser .bookmark-list *.scroll-bar:horizontal *.thumb,
|
||||||
.browser .bookmark-list *.scroll-bar:horizontal *.increment-button,
|
.browser .bookmark-list *.scroll-bar:horizontal *.increment-button,
|
||||||
.browser .bookmark-list *.scroll-bar:horizontal *.decrement-button,
|
.browser .bookmark-list *.scroll-bar:horizontal *.decrement-button,
|
||||||
.browser .bookmark-list *.scroll-bar:horizontal *.increment-arrow,
|
.browser .bookmark-list *.scroll-bar:horizontal *.increment-arrow,
|
||||||
.browser .bookmark-list *.scroll-bar:horizontal *.decrement-arrow {
|
.browser .bookmark-list *.scroll-bar:horizontal *.decrement-arrow {
|
||||||
-fx-background-color: null;
|
-fx-background-color: null;
|
||||||
-fx-background-radius: 0;
|
-fx-background-radius: 0;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
public interface GroupStore<T extends DataStore> extends DataStore {
|
public interface GroupStore<T extends DataStore> extends DataStore {
|
||||||
|
|
||||||
DataStoreEntryRef<T> getParent();
|
DataStoreEntryRef<? extends T> getParent();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void checkComplete() throws Exception {
|
default void checkComplete() throws Exception {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package io.xpipe.ext.base;
|
||||||
|
|
||||||
|
import io.xpipe.app.storage.DataStorage;
|
||||||
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface SelfReferentialStore extends DataStore {
|
||||||
|
|
||||||
|
default DataStoreEntry getSelfEntry() {
|
||||||
|
return DataStorage.get().getStoreEntries().stream().filter(dataStoreEntry -> dataStoreEntry.getStore() == this).findFirst().orElseGet(() -> {
|
||||||
|
return DataStoreEntry.createNew(UUID.randomUUID(),DataStorage.DEFAULT_CATEGORY_UUID, "Invalid", this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
package io.xpipe.ext.base.script;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
|
||||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
|
||||||
import io.xpipe.app.util.Validators;
|
|
||||||
import io.xpipe.core.process.ShellControl;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.experimental.SuperBuilder;
|
|
||||||
import lombok.extern.jackson.Jacksonized;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@SuperBuilder
|
|
||||||
@Getter
|
|
||||||
@Jacksonized
|
|
||||||
@JsonTypeName("multiScript")
|
|
||||||
public class MultiScriptStore extends ScriptStore {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prepareDumbScript(ShellControl shellControl) {
|
|
||||||
return getEffectiveScripts().stream().map(scriptStore -> {
|
|
||||||
return ((ScriptStore) scriptStore.getStore()).prepareDumbScript(shellControl);
|
|
||||||
}).filter(
|
|
||||||
Objects::nonNull).findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prepareTerminalScript(ShellControl shellControl) {
|
|
||||||
return getEffectiveScripts().stream().map(scriptStore -> {
|
|
||||||
return ((ScriptStore) scriptStore.getStore()).prepareDumbScript(shellControl);
|
|
||||||
}).filter(
|
|
||||||
Objects::nonNull).findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkComplete() throws Exception {
|
|
||||||
if (scripts != null) {
|
|
||||||
Validators.contentNonNull(scripts);
|
|
||||||
for (var script : scripts) {
|
|
||||||
script.getStore().checkComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts() {
|
|
||||||
return scripts != null ? scripts.stream().filter(scriptStore -> scriptStore != null).toList() : List.of();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
package io.xpipe.ext.base.script;
|
|
||||||
|
|
||||||
import io.xpipe.app.comp.storage.store.DenseStoreEntryComp;
|
|
||||||
import io.xpipe.app.comp.storage.store.StoreEntryWrapper;
|
|
||||||
import io.xpipe.app.comp.storage.store.StoreSection;
|
|
||||||
import io.xpipe.app.ext.DataStoreProvider;
|
|
||||||
import io.xpipe.app.ext.GuiDialog;
|
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
|
||||||
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
|
||||||
import io.xpipe.app.fxcomps.impl.DataStoreListChoiceComp;
|
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
|
||||||
import io.xpipe.app.util.OptionsBuilder;
|
|
||||||
import io.xpipe.core.store.DataStore;
|
|
||||||
import io.xpipe.core.util.Identifiers;
|
|
||||||
import javafx.beans.property.Property;
|
|
||||||
import javafx.beans.property.SimpleListProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MultiScriptStoreProvider implements DataStoreProvider {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Comp<?> customEntryComp(StoreSection s, boolean preferLarge) {
|
|
||||||
return new DenseStoreEntryComp(s.getWrapper(),true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean alwaysShowSummary() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldHaveChildren() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldEdit() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isShareable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CreationCategory getCreationCategory() {
|
|
||||||
return CreationCategory.SCRIPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return "multiScript";
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
|
||||||
public String getDisplayIconFileName(DataStore store) {
|
|
||||||
return "proc:shellEnvironment_icon.svg";
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
|
||||||
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
|
||||||
MultiScriptStore st = store.getValue().asNeeded();
|
|
||||||
var group = new SimpleObjectProperty<>(st.getGroup());
|
|
||||||
var others = new SimpleListProperty<>(FXCollections.observableArrayList(new ArrayList<>(st.getEffectiveScripts())));
|
|
||||||
return new OptionsBuilder()
|
|
||||||
.name("scriptGroup")
|
|
||||||
.description("scriptGroupDescription")
|
|
||||||
.addComp(DataStoreChoiceComp.other(group, ScriptGroupStore.class, null), group)
|
|
||||||
.name("snippets")
|
|
||||||
.description("snippetsDependenciesDescription")
|
|
||||||
.addComp(new DataStoreListChoiceComp<>(others, ScriptStore.class, scriptStore -> !scriptStore.get().equals(entry) && others.stream().noneMatch(scriptStoreDataStoreEntryRef -> scriptStoreDataStoreEntryRef.getStore().equals(scriptStore))), others)
|
|
||||||
.nonEmpty()
|
|
||||||
.bind(
|
|
||||||
() -> {
|
|
||||||
return MultiScriptStore.builder().group(group.get()).scripts(others.get()).description(st.getDescription()).build();
|
|
||||||
},
|
|
||||||
store)
|
|
||||||
.buildDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObservableValue<String> informationString(StoreEntryWrapper wrapper) {
|
|
||||||
MultiScriptStore st = wrapper.getEntry().getStore().asNeeded();
|
|
||||||
return new SimpleStringProperty(st.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataStoreEntry getDisplayParent(DataStoreEntry store) {
|
|
||||||
MultiScriptStore st = store.getStore().asNeeded();
|
|
||||||
return st.getGroup().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Class<?>> getStoreClasses() {
|
|
||||||
return List.of(MultiScriptStore.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataStore defaultStore() {
|
|
||||||
return MultiScriptStore.builder().scripts(List.of()).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getPossibleNames() {
|
|
||||||
return Identifiers.get("multiScript");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ import lombok.Setter;
|
||||||
@Getter
|
@Getter
|
||||||
public enum PredefinedScriptGroup {
|
public enum PredefinedScriptGroup {
|
||||||
CLINK("Clink", null),
|
CLINK("Clink", null),
|
||||||
STARSHIP("Starship", "Scripts to enable the starship shell extension");
|
STARSHIP("Starship", "Sets up and enables the starship shell prompt");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
|
@ -1,24 +1,40 @@
|
||||||
package io.xpipe.ext.base.script;
|
package io.xpipe.ext.base.script;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.core.store.DataStore;
|
|
||||||
import io.xpipe.core.util.JacksonizedValue;
|
|
||||||
import io.xpipe.ext.base.GroupStore;
|
import io.xpipe.ext.base.GroupStore;
|
||||||
|
import io.xpipe.ext.base.SelfReferentialStore;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
@Jacksonized
|
@Jacksonized
|
||||||
@JsonTypeName("scriptGroup")
|
@JsonTypeName("scriptGroup")
|
||||||
public class ScriptGroupStore extends JacksonizedValue implements GroupStore<DataStore> {
|
public class ScriptGroupStore extends ScriptStore implements GroupStore<ScriptStore>, SelfReferentialStore {
|
||||||
|
|
||||||
private final String description;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataStoreEntryRef<DataStore> getParent() {
|
public DataStoreEntryRef<? extends ScriptStore> getParent() {
|
||||||
return null;
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SimpleScriptStore> getFlattenedScripts(Set<SimpleScriptStore> seen) {
|
||||||
|
return getEffectiveScripts().stream().map(scriptStoreDataStoreEntryRef -> {
|
||||||
|
return scriptStoreDataStoreEntryRef.getStore().getFlattenedScripts(seen);
|
||||||
|
}).flatMap(List::stream).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts() {
|
||||||
|
var self = getSelfEntry();
|
||||||
|
return DataStorage.get().getStoreChildren(self, true).stream()
|
||||||
|
.map(dataStoreEntry -> dataStoreEntry.<ScriptStore>ref())
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,58 @@ import io.xpipe.app.comp.base.SystemStateComp;
|
||||||
import io.xpipe.app.comp.storage.store.DenseStoreEntryComp;
|
import io.xpipe.app.comp.storage.store.DenseStoreEntryComp;
|
||||||
import io.xpipe.app.comp.storage.store.StoreEntryWrapper;
|
import io.xpipe.app.comp.storage.store.StoreEntryWrapper;
|
||||||
import io.xpipe.app.comp.storage.store.StoreSection;
|
import io.xpipe.app.comp.storage.store.StoreSection;
|
||||||
|
import io.xpipe.app.comp.storage.store.StoreViewState;
|
||||||
import io.xpipe.app.ext.DataStoreProvider;
|
import io.xpipe.app.ext.DataStoreProvider;
|
||||||
|
import io.xpipe.app.ext.GuiDialog;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
|
import io.xpipe.app.fxcomps.impl.DataStoreChoiceComp;
|
||||||
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
|
import io.xpipe.app.util.OptionsBuilder;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
|
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;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ScriptGroupStoreProvider implements DataStoreProvider {
|
public class ScriptGroupStoreProvider implements DataStoreProvider {
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
||||||
|
ScriptGroupStore st = store.getValue().asNeeded();
|
||||||
|
|
||||||
|
var group = new SimpleObjectProperty<>(st.getGroup());
|
||||||
|
Property<String> description = new SimpleObjectProperty<>(st.getDescription());
|
||||||
|
return new OptionsBuilder()
|
||||||
|
.name("description")
|
||||||
|
.description("descriptionDescription")
|
||||||
|
.addString(description)
|
||||||
|
.name("scriptGroup")
|
||||||
|
.description("scriptGroupDescription")
|
||||||
|
.addComp(
|
||||||
|
new DataStoreChoiceComp<>(
|
||||||
|
DataStoreChoiceComp.Mode.OTHER, null, group, ScriptGroupStore.class, ref->! ref.getEntry().equals(entry), StoreViewState.get().getAllScriptsCategory()),
|
||||||
|
group)
|
||||||
|
.nonNull()
|
||||||
|
.bind(
|
||||||
|
() -> {
|
||||||
|
return ScriptGroupStore.builder()
|
||||||
|
.group(group.get())
|
||||||
|
.description(st.getDescription())
|
||||||
|
.build();
|
||||||
|
},
|
||||||
|
store)
|
||||||
|
.buildDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataStore defaultStore() {
|
||||||
|
return ScriptGroupStore.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Comp<?> stateDisplay(StoreEntryWrapper w) {
|
public Comp<?> stateDisplay(StoreEntryWrapper w) {
|
||||||
return new SystemStateComp(new SimpleObjectProperty<>(SystemStateComp.State.SUCCESS));
|
return new SystemStateComp(new SimpleObjectProperty<>(SystemStateComp.State.SUCCESS));
|
||||||
|
|
|
@ -13,8 +13,10 @@ import lombok.experimental.FieldDefaults;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
|
@ -22,19 +24,22 @@ import java.util.stream.Collectors;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public abstract class ScriptStore extends JacksonizedValue implements DataStore, StatefulDataStore<ScriptStore.State> {
|
public abstract class ScriptStore extends JacksonizedValue implements DataStore, StatefulDataStore<ScriptStore.State> {
|
||||||
|
|
||||||
|
|
||||||
public static ShellControl controlWithDefaultScripts(ShellControl pc) {
|
public static ShellControl controlWithDefaultScripts(ShellControl pc) {
|
||||||
|
return controlWithScripts(pc,getDefaultScripts());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShellControl controlWithScripts(ShellControl pc, List<DataStoreEntryRef<ScriptStore>> refs) {
|
||||||
pc.onInit(shellControl -> {
|
pc.onInit(shellControl -> {
|
||||||
var scripts = getDefaultScripts().stream()
|
var scripts = flatten(refs).stream()
|
||||||
.map(simpleScriptStore -> simpleScriptStore.getStore().prepareDumbScript(shellControl))
|
.map(simpleScriptStore -> simpleScriptStore.prepareDumbScript(shellControl))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.joining("\n"));
|
.collect(Collectors.joining("\n"));
|
||||||
if (!scripts.isBlank()) {
|
if (!scripts.isBlank()) {
|
||||||
shellControl.executeSimpleBooleanCommand(scripts);
|
shellControl.executeSimpleBooleanCommand(scripts);
|
||||||
}
|
}
|
||||||
|
|
||||||
var terminalCommands = getDefaultScripts().stream()
|
var terminalCommands = flatten(refs).stream()
|
||||||
.map(simpleScriptStore -> simpleScriptStore.getStore().prepareTerminalScript(shellControl))
|
.map(simpleScriptStore -> simpleScriptStore.prepareTerminalScript(shellControl))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.joining("\n"));
|
.collect(Collectors.joining("\n"));
|
||||||
if (!terminalCommands.isBlank()) {
|
if (!terminalCommands.isBlank()) {
|
||||||
|
@ -44,14 +49,21 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore,
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<DataStoreEntryRef<ScriptStore>> getDefaultScripts() {
|
private static List<DataStoreEntryRef<ScriptStore>> getDefaultScripts() {
|
||||||
var list = DataStorage.get().getStoreEntries().stream()
|
return DataStorage.get().getStoreEntries().stream()
|
||||||
.filter(dataStoreEntry -> dataStoreEntry.getStore() instanceof ScriptStore scriptStore
|
.filter(dataStoreEntry -> dataStoreEntry.getStore() instanceof ScriptStore scriptStore
|
||||||
&& scriptStore.getState().isDefault())
|
&& scriptStore.getState().isDefault())
|
||||||
.map(e -> e.<ScriptStore>ref())
|
.map(e -> e.<ScriptStore>ref())
|
||||||
.toList();
|
.toList();
|
||||||
// TODO: Make unique
|
}
|
||||||
return list;
|
|
||||||
|
public static List<SimpleScriptStore> flatten(List<DataStoreEntryRef<ScriptStore>> scripts) {
|
||||||
|
var seen = new HashSet<SimpleScriptStore>();
|
||||||
|
return scripts.stream()
|
||||||
|
.map(scriptStoreDataStoreEntryRef ->
|
||||||
|
scriptStoreDataStoreEntryRef.getStore().getFlattenedScripts(seen))
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final DataStoreEntryRef<ScriptGroupStore> group;
|
protected final DataStoreEntryRef<ScriptGroupStore> group;
|
||||||
|
@ -83,9 +95,11 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract String prepareDumbScript(ShellControl shellControl);
|
public List<SimpleScriptStore> getFlattenedScripts() {
|
||||||
|
return getFlattenedScripts(new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
public abstract String prepareTerminalScript(ShellControl shellControl);
|
protected abstract List<SimpleScriptStore> getFlattenedScripts(Set<SimpleScriptStore> seen);
|
||||||
|
|
||||||
public abstract List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts();
|
public abstract List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,9 @@ import lombok.Getter;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiFunction;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -22,37 +21,47 @@ import java.util.function.BiFunction;
|
||||||
@JsonTypeName("script")
|
@JsonTypeName("script")
|
||||||
public class SimpleScriptStore extends ScriptStore {
|
public class SimpleScriptStore extends ScriptStore {
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prepareDumbScript(ShellControl shellControl) {
|
public String prepareDumbScript(ShellControl shellControl) {
|
||||||
return assemble(shellControl, ExecutionType.DUMB_ONLY, ScriptStore::prepareDumbScript);
|
return assemble(shellControl, ExecutionType.DUMB_ONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String prepareTerminalScript(ShellControl shellControl) {
|
public String prepareTerminalScript(ShellControl shellControl) {
|
||||||
return assemble(shellControl, ExecutionType.TERMINAL_ONLY, ScriptStore::prepareTerminalScript);
|
return assemble(shellControl, ExecutionType.TERMINAL_ONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String assemble(ShellControl shellControl, ExecutionType type, BiFunction<ScriptStore, ShellControl, String> function) {
|
private String assemble(
|
||||||
var list = new ArrayList<String>();
|
ShellControl shellControl, ExecutionType type) {
|
||||||
scripts.forEach(scriptStoreDataStoreEntryRef -> {
|
if ((executionType == type || executionType == ExecutionType.BOTH)
|
||||||
var s = function.apply(scriptStoreDataStoreEntryRef.getStore(), shellControl);
|
&& minimumDialect.isCompatibleTo(shellControl.getShellDialect())) {
|
||||||
if (s != null) {
|
|
||||||
list.add(s);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if ((executionType == type || executionType == ExecutionType.BOTH) && minimumDialect.isCompatibleTo(shellControl.getShellDialect())) {
|
|
||||||
var script = ScriptHelper.createExecScript(minimumDialect, shellControl, commands);
|
var script = ScriptHelper.createExecScript(minimumDialect, shellControl, commands);
|
||||||
list.add(shellControl.getShellDialect().sourceScriptCommand(shellControl, script));
|
return shellControl.getShellDialect().sourceScriptCommand(shellControl, script);
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmd = String.join("\n", list);
|
return null;
|
||||||
return cmd.isEmpty() ? null : cmd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts() {
|
public List<DataStoreEntryRef<ScriptStore>> getEffectiveScripts() {
|
||||||
return scripts != null ? scripts.stream().filter(scriptStore -> scriptStore != null).toList() : List.of();
|
return scripts != null
|
||||||
|
? scripts.stream().filter(scriptStore -> scriptStore != null).toList()
|
||||||
|
: List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SimpleScriptStore> getFlattenedScripts(Set<SimpleScriptStore> seen) {
|
||||||
|
var isLoop = seen.contains(this);
|
||||||
|
seen.add(this);
|
||||||
|
return Stream.concat(
|
||||||
|
getEffectiveScripts().stream()
|
||||||
|
.map(scriptStoreDataStoreEntryRef -> {
|
||||||
|
return scriptStoreDataStoreEntryRef.getStore().getFlattenedScripts(seen).stream()
|
||||||
|
.filter(simpleScriptStore -> !seen.contains(simpleScriptStore))
|
||||||
|
.peek(simpleScriptStore -> seen.add(simpleScriptStore))
|
||||||
|
.toList();
|
||||||
|
})
|
||||||
|
.flatMap(List::stream),
|
||||||
|
isLoop ? Stream.of() : Stream.of(this))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|
|
@ -7,6 +7,7 @@ import io.xpipe.app.comp.base.SystemStateComp;
|
||||||
import io.xpipe.app.comp.storage.store.DenseStoreEntryComp;
|
import io.xpipe.app.comp.storage.store.DenseStoreEntryComp;
|
||||||
import io.xpipe.app.comp.storage.store.StoreEntryWrapper;
|
import io.xpipe.app.comp.storage.store.StoreEntryWrapper;
|
||||||
import io.xpipe.app.comp.storage.store.StoreSection;
|
import io.xpipe.app.comp.storage.store.StoreSection;
|
||||||
|
import io.xpipe.app.comp.storage.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;
|
||||||
|
@ -50,11 +51,6 @@ public class SimpleScriptStoreProvider implements DataStoreProvider {
|
||||||
return new DenseStoreEntryComp(sec.getWrapper(), true, dropdown);
|
return new DenseStoreEntryComp(sec.getWrapper(), true, dropdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean alwaysShowSummary() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldHaveChildren() {
|
public boolean shouldHaveChildren() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -132,7 +128,8 @@ public class SimpleScriptStoreProvider implements DataStoreProvider {
|
||||||
new DataStoreListChoiceComp<>(
|
new DataStoreListChoiceComp<>(
|
||||||
others,
|
others,
|
||||||
ScriptStore.class,
|
ScriptStore.class,
|
||||||
scriptStore -> !scriptStore.get().equals(entry) && !others.contains(scriptStore)),
|
scriptStore -> !scriptStore.get().equals(entry) && !others.contains(scriptStore), StoreViewState.get().getAllScriptsCategory()
|
||||||
|
),
|
||||||
others)
|
others)
|
||||||
.name("minimumShellDialect")
|
.name("minimumShellDialect")
|
||||||
.description("minimumShellDialectDescription")
|
.description("minimumShellDialectDescription")
|
||||||
|
@ -160,7 +157,7 @@ public class SimpleScriptStoreProvider implements DataStoreProvider {
|
||||||
.description("scriptGroupDescription")
|
.description("scriptGroupDescription")
|
||||||
.addComp(
|
.addComp(
|
||||||
new DataStoreChoiceComp<>(
|
new DataStoreChoiceComp<>(
|
||||||
DataStoreChoiceComp.Mode.OTHER, null, group, ScriptGroupStore.class, null),
|
DataStoreChoiceComp.Mode.OTHER, null, group, ScriptGroupStore.class, null, StoreViewState.get().getAllScriptsCategory()),
|
||||||
group)
|
group)
|
||||||
.nonNull()
|
.nonNull()
|
||||||
.bind(
|
.bind(
|
||||||
|
@ -180,31 +177,30 @@ public class SimpleScriptStoreProvider implements DataStoreProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String summaryString(StoreEntryWrapper wrapper) {
|
public boolean canMoveCategories() {
|
||||||
SimpleScriptStore scriptStore = wrapper.getEntry().getStore().asNeeded();
|
return false;
|
||||||
return (scriptStore.isRequiresElevation() ? "Elevated " : "")
|
|
||||||
+ (scriptStore.getMinimumDialect() != null
|
|
||||||
? scriptStore.getMinimumDialect().getDisplayName() + " "
|
|
||||||
: "")
|
|
||||||
+ (scriptStore.getExecutionType() == SimpleScriptStore.ExecutionType.TERMINAL_ONLY
|
|
||||||
? "Terminal"
|
|
||||||
: scriptStore.getExecutionType() == SimpleScriptStore.ExecutionType.DUMB_ONLY
|
|
||||||
? "Background"
|
|
||||||
: "")
|
|
||||||
+ " Snippet";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObservableValue<String> informationString(StoreEntryWrapper wrapper) {
|
public ObservableValue<String> informationString(StoreEntryWrapper wrapper) {
|
||||||
SimpleScriptStore scriptStore = wrapper.getEntry().getStore().asNeeded();
|
SimpleScriptStore scriptStore = wrapper.getEntry().getStore().asNeeded();
|
||||||
return new SimpleStringProperty(scriptStore.getDescription());
|
return new SimpleStringProperty((scriptStore.isRequiresElevation() ? "Elevated " : "")
|
||||||
|
+ (scriptStore.getMinimumDialect() != null
|
||||||
|
? scriptStore.getMinimumDialect().getDisplayName() + " "
|
||||||
|
: "")
|
||||||
|
+ (scriptStore.getExecutionType() == SimpleScriptStore.ExecutionType.TERMINAL_ONLY
|
||||||
|
? "Terminal"
|
||||||
|
: scriptStore.getExecutionType() == SimpleScriptStore.ExecutionType.DUMB_ONLY
|
||||||
|
? "Background"
|
||||||
|
: "")
|
||||||
|
+ " Snippet");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void storageInit() throws Exception {
|
public void storageInit() throws Exception {
|
||||||
var cat = DataStorage.get()
|
var cat = DataStorage.get()
|
||||||
.addStoreCategoryIfNotPresent(DataStoreCategory.createNew(
|
.addStoreCategoryIfNotPresent(DataStoreCategory.createNew(
|
||||||
DataStorage.SCRIPTS_CATEGORY_UUID, DataStorage.CUSTOM_SCRIPTS_CATEGORY_UUID, "My scripts"));
|
DataStorage.ALL_SCRIPTS_CATEGORY_UUID, DataStorage.CUSTOM_SCRIPTS_CATEGORY_UUID, "My scripts"));
|
||||||
DataStorage.get()
|
DataStorage.get()
|
||||||
.addStoreEntryIfNotPresent(DataStoreEntry.createNew(
|
.addStoreEntryIfNotPresent(DataStoreEntry.createNew(
|
||||||
UUID.fromString("a9945ad2-db61-4304-97d7-5dc4330691a7"),
|
UUID.fromString("a9945ad2-db61-4304-97d7-5dc4330691a7"),
|
||||||
|
|
|
@ -24,7 +24,9 @@ newDirectory=New directory
|
||||||
copyShareLink=Copy link
|
copyShareLink=Copy link
|
||||||
selectStore=Select Store
|
selectStore=Select Store
|
||||||
saveSource=Save for later
|
saveSource=Save for later
|
||||||
deleteChildren=Remove children
|
execute=Execute
|
||||||
|
deleteChildren=Remove all children
|
||||||
|
descriptionDescription=Give this group an optional description
|
||||||
selectSource=Select Source
|
selectSource=Select Source
|
||||||
commandLineRead=Update
|
commandLineRead=Update
|
||||||
commandLineWrite=Write
|
commandLineWrite=Write
|
||||||
|
|
Loading…
Reference in a new issue