diff --git a/app/src/main/java/io/xpipe/app/ext/EnabledParentStoreProvider.java b/app/src/main/java/io/xpipe/app/ext/EnabledParentStoreProvider.java deleted file mode 100644 index d3a15a896..000000000 --- a/app/src/main/java/io/xpipe/app/ext/EnabledParentStoreProvider.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.xpipe.app.ext; - -import io.xpipe.app.hub.comp.StoreEntryComp; -import io.xpipe.app.hub.comp.StoreSection; -import io.xpipe.app.hub.comp.StoreToggleComp; -import io.xpipe.app.hub.comp.StoreViewState; -import io.xpipe.app.platform.BindingsHelper; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.app.util.ThreadHelper; - -import javafx.beans.property.SimpleBooleanProperty; - -public interface EnabledParentStoreProvider extends DataStoreProvider { - - @Override - default StoreEntryComp customEntryComp(StoreSection sec, boolean preferLarge) { - if (sec.getWrapper().getValidity().getValue() == DataStoreEntry.Validity.LOAD_FAILED) { - return StoreEntryComp.create(sec, null, preferLarge); - } - - EnabledStoreState initialState = sec.getWrapper().getEntry().getStorePersistentState(); - var enabled = new SimpleBooleanProperty(initialState.isEnabled()); - sec.getWrapper().getPersistentState().subscribe((newValue) -> { - EnabledStoreState s = sec.getWrapper().getEntry().getStorePersistentState(); - enabled.set(s.isEnabled()); - }); - - var toggle = StoreToggleComp.>enableToggle( - null, sec, enabled, (s, aBoolean) -> { - var state = s.getState().toBuilder().enabled(aBoolean).build(); - s.setState(state); - - var children = - DataStorage.get().getStoreChildren(sec.getWrapper().getEntry()); - ThreadHelper.runFailableAsync(() -> { - for (DataStoreEntry child : children) { - if (child.getStorePersistentState() instanceof EnabledStoreState enabledStoreState) { - child.setStorePersistentState(enabledStoreState.toBuilder() - .enabled(aBoolean) - .build()); - } - } - }); - }); - - var e = sec.getWrapper().getEntry(); - var parent = DataStorage.get().getDefaultDisplayParent(e); - if (parent.isPresent()) { - var parentWrapper = StoreViewState.get().getEntryWrapper(parent.get()); - // Disable selection if parent is already made enabled - toggle.setCustomVisibility(BindingsHelper.map(parentWrapper.getPersistentState(), o -> { - EnabledStoreState state = (EnabledStoreState) o; - return !state.isEnabled(); - })); - } - - return StoreEntryComp.create(sec, toggle, preferLarge); - } -} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptGroup.java b/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptGroup.java deleted file mode 100644 index 4c8aa2070..000000000 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptGroup.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.xpipe.ext.base.script; - -import io.xpipe.app.storage.DataStoreEntryRef; - -import lombok.Getter; -import lombok.Setter; - -@Getter -public enum PredefinedScriptGroup { - MANAGEMENT("Management", "Sample management scripts", true), - FILES("Files", "Sample scripts for files", true); - - private final String name; - private final String description; - private final boolean expanded; - - @Setter - private DataStoreEntryRef entry; - - PredefinedScriptGroup(String name, String description, boolean expanded) { - this.name = name; - this.description = description; - this.expanded = expanded; - } -} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java index b75a423d0..ea496b0dd 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java @@ -18,29 +18,24 @@ import java.util.function.Supplier; @Getter public enum PredefinedScriptStore { APT_UPDATE("Apt upgrade", () -> ScriptStore.builder() - .group(PredefinedScriptGroup.MANAGEMENT.getEntry()) .textSource(ScriptTextSource.InPlace.builder().dialect(ShellDialects.SH).text(file("apt_upgrade.sh")).build()) .shellScript(true) .runnableScript(true) .build()), REMOVE_CR("CRLF to LF", () -> ScriptStore.builder() - .group(PredefinedScriptGroup.FILES.getEntry()) .textSource(ScriptTextSource.InPlace.builder().dialect(ShellDialects.SH).text(file("crlf_to_lf.sh")).build()) .fileScript(true) .shellScript(true) .build()), DIFF("Diff", () -> ScriptStore.builder() - .group(PredefinedScriptGroup.FILES.getEntry()) .textSource(ScriptTextSource.InPlace.builder().dialect(ShellDialects.SH).text(file("diff.sh")).build()) .fileScript(true) .build()), GIT_CONFIG("Git Config", () -> ScriptStore.builder() - .group(PredefinedScriptGroup.MANAGEMENT.getEntry()) .textSource(ScriptTextSource.InPlace.builder().text(file("git_config.sh")).build()) .runnableScript(true) .build()), SYSTEM_HEALTH_STATUS("System health status", () -> ScriptStore.builder() - .group(PredefinedScriptGroup.MANAGEMENT.getEntry()) .textSource(ScriptTextSource.InPlace.builder().dialect(ShellDialects.SH).text(file("system_health.sh")).build()) .initScript(true) .build()); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/RunFileScriptMenuProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/RunFileScriptMenuProvider.java index adff7d398..de66ea578 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/RunFileScriptMenuProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/RunFileScriptMenuProvider.java @@ -95,7 +95,7 @@ public class RunFileScriptMenuProvider implements BrowserMenuBranchProvider { private BrowserMenuBranchProvider createActionForScriptHierarchy(ScriptHierarchy hierarchy) { if (hierarchy.isLeaf()) { - return createActionForScript(hierarchy.getLeafBase()); + return createActionForScript(hierarchy.getScript()); } var list = hierarchy.getChildren().stream() @@ -104,14 +104,17 @@ public class RunFileScriptMenuProvider implements BrowserMenuBranchProvider { return new BrowserMenuBranchProvider() { @Override public LabelGraphic getIcon() { + if (!hierarchy.isLeaf()) { + return null; + } + return new LabelGraphic.CompGraphic( - PrettyImageHelper.ofFixedSize(hierarchy.getBase().get().getEffectiveIconFile(), 16, 16)); + PrettyImageHelper.ofFixedSize(hierarchy.getScript().get().getEffectiveIconFile(), 16, 16)); } @Override public ObservableValue getName(BrowserFileSystemTabModel model, List entries) { - var b = hierarchy.getBase(); - return new SimpleStringProperty(b != null ? b.get().getName() : null); + return new SimpleStringProperty(hierarchy.getName()); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/RunScriptActionProviderMenu.java b/ext/base/src/main/java/io/xpipe/ext/base/script/RunScriptActionProviderMenu.java index 92ff16b1c..7bb99c399 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/RunScriptActionProviderMenu.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/RunScriptActionProviderMenu.java @@ -15,6 +15,7 @@ import io.xpipe.app.process.SystemState; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntryRef; +import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; @@ -172,7 +173,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider ref) { return RunTerminalScriptActionProvider.Action.builder() .ref(ref) - .scriptStore(hierarchy.getLeafBase()) + .scriptStore(hierarchy.getScript()) .build(); } @@ -214,7 +215,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider ref) { return RunTerminalScriptActionProvider.Action.builder() .ref(ref) - .scriptStore(hierarchy.getLeafBase()) + .scriptStore(hierarchy.getScript()) .build(); } } @@ -228,7 +229,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider ref) { return RunHubScriptActionProvider.Action.builder() .ref(ref) - .scriptStore(hierarchy.getLeafBase()) + .scriptStore(hierarchy.getScript()) .build(); } @@ -266,7 +267,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider> stores) { return RunHubBatchScriptActionProvider.Action.builder() .refs(stores) - .scriptStore(hierarchy.getLeafBase()) + .scriptStore(hierarchy.getScript()) .build(); } @@ -274,7 +275,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider ref) { return RunHubScriptActionProvider.Action.builder() .ref(ref) - .scriptStore(hierarchy.getLeafBase()) + .scriptStore(hierarchy.getScript()) .build(); } } @@ -289,7 +290,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider ref) { return RunBackgroundScriptActionProvider.Action.builder() .ref(ref) - .scriptStore(hierarchy.getLeafBase()) + .scriptStore(hierarchy.getScript()) .build(); } @@ -327,7 +328,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider ref) { return RunBackgroundScriptActionProvider.Action.builder() .ref(ref) - .scriptStore(hierarchy.getLeafBase()) + .scriptStore(hierarchy.getScript()) .build(); } @@ -344,16 +345,16 @@ public class RunScriptActionProviderMenu implements HubBranchProvider getName() { - return new SimpleStringProperty(hierarchy.getBase().get().getName()); + return new ReadOnlyObjectWrapper<>(hierarchy.getName()); } @Override public LabelGraphic getIcon() { if (hierarchy.isLeaf()) { - return new LabelGraphic.ImageGraphic(hierarchy.getBase().get().getEffectiveIconFile(), 16); + return new LabelGraphic.ImageGraphic(hierarchy.getScript().get().getEffectiveIconFile(), 16); } - return new LabelGraphic.IconGraphic("mdi2p-play-box-multiple-outline"); + return new LabelGraphic.ImageGraphic("base:scriptGroup_icon.svg", 16); } @Override diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceImportDialog.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceImportDialog.java index 11b9c0d49..55c12d5be 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceImportDialog.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptCollectionSourceImportDialog.java @@ -5,9 +5,7 @@ import io.xpipe.app.comp.base.*; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.ShellDialectChoiceComp; import io.xpipe.app.ext.ShellDialectIcons; -import io.xpipe.app.hub.comp.StoreChoiceComp; -import io.xpipe.app.hub.comp.StoreCreationDialog; -import io.xpipe.app.hub.comp.StoreViewState; +import io.xpipe.app.hub.comp.*; import io.xpipe.app.issue.ErrorEventFactory; import io.xpipe.app.platform.DerivedObservableList; import io.xpipe.app.platform.LabelGraphic; @@ -43,7 +41,7 @@ public class ScriptCollectionSourceImportDialog { private final StringProperty filter = new SimpleStringProperty(); private final BooleanProperty busy = new SimpleBooleanProperty(); private final IntegerProperty count = new SimpleIntegerProperty(); - private final ObjectProperty> targetGroup = new SimpleObjectProperty<>(); + private final ObjectProperty targetCategory = new SimpleObjectProperty<>(); public ScriptCollectionSourceImportDialog(DataStoreEntryRef source) { this.source = source; @@ -98,33 +96,10 @@ public class ScriptCollectionSourceImportDialog { stack.prefWidth(600); stack.prefHeight(650); - var storeChoice = new StoreChoiceComp<>( - null, - targetGroup, - ScriptGroupStore.class, - null, - StoreViewState.get().getAllScriptsCategory(), - StoreViewState.get().getAllScriptsCategory()) { - @Override - protected String toName(DataStoreEntry entry) { - if (entry == null) { - return AppI18n.get("selectCategory"); - } else { - return super.toName(entry); - } - } - - @Override - protected String toGraphic(DataStoreEntry entry) { - if (entry == null) { - return "scriptGroup_icon.svg"; - } else { - return super.toGraphic(entry); - } - } - }; - storeChoice.hgrow(); - storeChoice.maxHeight(100); + var catChoice = new DataStoreCategoryChoiceComp(StoreViewState.get().getAllScriptsCategory(), + StoreViewState.get().getActiveCategory(), targetCategory, false); + catChoice.hgrow(); + catChoice.maxHeight(100); var modal = ModalOverlay.of( Bindings.createStringBinding(() -> { @@ -134,19 +109,18 @@ public class ScriptCollectionSourceImportDialog { null); modal.addButtonBarComp(refresh); modal.addButtonBarComp(filterField); - modal.addButtonBarComp(storeChoice); + modal.addButtonBarComp(catChoice); modal.addButton(ModalButton.ok(() -> { ThreadHelper.runAsync(() -> { finish(); }); })) - .augment(button -> button.disableProperty().bind(Bindings.isEmpty(selected).or(targetGroup.isNull()))); + .augment(button -> button.disableProperty().bind(Bindings.isEmpty(selected).or(targetCategory.isNull()))); modal.show(); } private void finish() { - var targetCat = DataStorage.get().getStoreCategory(targetGroup.getValue().get()); - StoreViewState.get().selectCategoryIntoViewIfNeeded(StoreViewState.get().getCategoryWrapper(targetCat)); + StoreViewState.get().selectCategoryIntoViewIfNeeded(targetCategory.getValue()); var added = new ArrayList(); for (ScriptCollectionSourceEntry e : selected) { @@ -159,7 +133,7 @@ public class ScriptCollectionSourceImportDialog { continue; } - var store = ScriptStore.builder().textSource(textSource).group(targetGroup.get()).build(); + var store = ScriptStore.builder().textSource(textSource).build(); var entry = DataStoreEntry.createNew(name, store); DataStorage.get().addStoreEntryIfNotPresent(entry); added.add(entry); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptDataStorageProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptDataStorageProvider.java index fa463f243..6c68130ed 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptDataStorageProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptDataStorageProvider.java @@ -21,28 +21,6 @@ public class ScriptDataStorageProvider extends DataStorageExtensionProvider { return; } - DataStorage.get() - .addStoreEntryIfNotPresent(DataStoreEntry.createNew( - UUID.fromString("a9945ad2-db61-4304-97d7-5dc4330691a7"), - DataStorage.CUSTOM_SCRIPTS_CATEGORY_UUID, - "My scripts", - ScriptGroupStore.builder().build())); - - for (PredefinedScriptGroup value : PredefinedScriptGroup.values()) { - ScriptGroupStore store = ScriptGroupStore.builder() - .description(value.getDescription()) - .build(); - var e = DataStorage.get() - .addStoreEntryIfNotPresent(DataStoreEntry.createNew( - UUID.nameUUIDFromBytes(("a " + value.getName()).getBytes(StandardCharsets.UTF_8)), - DataStorage.PREDEFINED_SCRIPTS_CATEGORY_UUID, - value.getName(), - store)); - DataStorage.get().updateEntryStore(e, store); - e.setExpanded(value.isExpanded()); - value.setEntry(e.ref()); - } - for (PredefinedScriptStore value : PredefinedScriptStore.values()) { var previous = DataStorage.get().getStoreEntryIfPresent(value.getUuid()); var store = value.getScriptStore().get(); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptGroupStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptGroupStore.java deleted file mode 100644 index 20d9edcd8..000000000 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptGroupStore.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.xpipe.ext.base.script; - -import io.xpipe.app.ext.EnabledStoreState; -import io.xpipe.app.ext.GroupStore; -import io.xpipe.app.ext.SelfReferentialStore; -import io.xpipe.app.ext.StatefulDataStore; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.app.storage.DataStoreEntryRef; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import io.xpipe.app.util.Validators; -import lombok.EqualsAndHashCode; -import lombok.Singular; -import lombok.ToString; -import lombok.Value; -import lombok.experimental.SuperBuilder; -import lombok.extern.jackson.Jacksonized; - -import java.util.LinkedHashSet; -import java.util.List; - -@Value -@SuperBuilder -@Jacksonized -@JsonTypeName("scriptGroup") -public class ScriptGroupStore implements GroupStore, SelfReferentialStore, StatefulDataStore { - - DataStoreEntryRef group; - - String description; - - @Override - public Class getStateClass() { - return EnabledStoreState.class; - } - - @Override - public void checkComplete() throws Throwable { - if (group != null) { - Validators.isType(group, ScriptGroupStore.class); - } - } - @Override - public DataStoreEntryRef getParent() { - return group; - } -} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptGroupStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptGroupStoreProvider.java deleted file mode 100644 index 14e9e06e5..000000000 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptGroupStoreProvider.java +++ /dev/null @@ -1,102 +0,0 @@ -package io.xpipe.ext.base.script; - - -import io.xpipe.app.comp.BaseRegionBuilder; -import io.xpipe.app.ext.*; -import io.xpipe.app.hub.comp.*; -import io.xpipe.app.platform.OptionsBuilder; -import io.xpipe.app.storage.DataStoreCategory; -import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.app.util.DocumentationLink; - -import javafx.beans.property.Property; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.value.ObservableValue; - -import lombok.SneakyThrows; - -import java.util.List; - -public class ScriptGroupStoreProvider implements EnabledParentStoreProvider, DataStoreProvider { - - @Override - public DocumentationLink getHelpLink() { - return DocumentationLink.SCRIPTING; - } - - @Override - public BaseRegionBuilder stateDisplay(StoreEntryWrapper w) { - return new SystemStateComp(new SimpleObjectProperty<>(SystemStateComp.State.SUCCESS)); - } - - @Override - public DataStoreCreationCategory getCreationCategory() { - return DataStoreCreationCategory.SCRIPT; - } - - @Override - public DataStoreUsageCategory getUsageCategory() { - return DataStoreUsageCategory.GROUP; - } - - @Override - public DataStoreEntry getDisplayParent(DataStoreEntry store) { - ScriptGroupStore scriptStore = store.getStore().asNeeded(); - return scriptStore.getParent() != null ? scriptStore.getParent().get() : null; - } - - @SneakyThrows - @Override - public GuiDialog guiDialog(DataStoreEntry entry, Property store) { - ScriptGroupStore st = store.getValue().asNeeded(); - - var group = new SimpleObjectProperty<>(st.getGroup()); - var description = new SimpleObjectProperty<>(st.getDescription()); - return new OptionsBuilder() - .name("description") - .description("scriptGroupDescriptionDescription") - .addString(description) - .name("scriptGroup") - .description("scriptGroupGroupDescription") - .addComp( - new StoreChoiceComp<>( - entry, - group, - ScriptGroupStore.class, - null, - StoreViewState.get().getAllScriptsCategory()), - group) - .bind( - () -> { - return ScriptGroupStore.builder() - .group(group.get()) - .description(description.getValue()) - .build(); - }, - store) - .buildDialog(); - } - - @Override - public ObservableValue informationString(StoreSection section) { - ScriptGroupStore scriptStore = - section.getWrapper().getEntry().getStore().asNeeded(); - return new SimpleStringProperty(scriptStore.getDescription()); - } - - @Override - public DataStore defaultStore(DataStoreCategory category) { - return ScriptGroupStore.builder().build(); - } - - @Override - public String getId() { - return "scriptGroup"; - } - - @Override - public List> getStoreClasses() { - return List.of(ScriptGroupStore.class); - } -} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptHierarchy.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptHierarchy.java index 62a0a6de5..6b0267099 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptHierarchy.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptHierarchy.java @@ -1,81 +1,108 @@ package io.xpipe.ext.base.script; import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreEntryRef; import lombok.Value; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; +import java.util.*; import java.util.function.Predicate; @Value public class ScriptHierarchy { - DataStoreEntryRef base; + String name; + DataStoreCategory category; + DataStoreEntryRef script; List children; public static ScriptHierarchy buildEnabledHierarchy(Predicate> include) { - var enabled = ScriptStoreSetup.getEnabledScripts(); - var all = new HashSet>(ScriptStoreSetup.getEnabledScripts()); + var enabled = ScriptStoreSetup.getEnabledScripts().stream().filter(include).toList(); - // Add parents + var categories = new HashSet(); for (DataStoreEntryRef ref : enabled) { - DataStoreEntryRef current = ref; - while (true) { - var parent = DataStorage.get().getDefaultDisplayParent(current.get()); - if (parent.isPresent()) { - DataStoreEntryRef next = parent.get().ref(); - all.add(next); - current = next; - } else { - break; + var cat = DataStorage.get().getStoreCategory(ref.get()); + var catParents = DataStorage.get().getCategoryParentHierarchy(cat); + categories.addAll(catParents); + } + + var hierarchy = new ScriptHierarchy(null, null, null, new ArrayList<>()); + while (true) { + var changed = false; + for (DataStoreCategory cat : categories) { + // We don't support the All Scripts root + if (cat.getParentCategory() == null) { + continue; } + + var toAdd = new ScriptHierarchy(cat.getName(), cat, null, new ArrayList<>()); + + if (cat.getParentCategory().equals(DataStorage.ALL_SCRIPTS_CATEGORY_UUID)) { + if (!hierarchy.getChildren().contains(toAdd)) { + hierarchy.getChildren().add(toAdd); + changed = true; + } + continue; + } + + var parentHierarchy = findParent(hierarchy, cat); + if (parentHierarchy.isEmpty()) { + continue; + } + + var alreadyAdded = parentHierarchy.get().getChildren().contains(toAdd); + if (alreadyAdded) { + continue; + } + + parentHierarchy.get().getChildren().add(toAdd); + changed = true; + } + + if (!changed) { + break; } } - var top = all.stream() - .filter(ref -> { - var parent = DataStorage.get().getDefaultDisplayParent(ref.get()); - return parent.isEmpty(); - }) - .toList(); + for (DataStoreEntryRef scriptRef : enabled) { + var scriptCategory = DataStorage.get().getStoreCategory(scriptRef.get()); + var catHierarchy = findParent(hierarchy, scriptCategory); + if (catHierarchy.isEmpty()) { + continue; + } - var mapped = top.stream() - .map(ref -> buildHierarchy(ref, check -> { - if (!include.test(check.asNeeded())) { - return false; - } + var childTarget = catHierarchy.get().getChildren().stream() + .filter(child -> child.getCategory().equals(scriptCategory)) + .findFirst(); + if (childTarget.isEmpty()) { + continue; + } - return all.contains(check); - })) - .map(hierarchy -> condenseHierarchy(hierarchy)) - .filter(hierarchy -> hierarchy.show()) - .sorted(Comparator.comparing(scriptHierarchy -> - scriptHierarchy.getBase().get().getName().toLowerCase())) - .toList(); - return condenseHierarchy(new ScriptHierarchy(null, mapped)); + childTarget.get().getChildren().add(new ScriptHierarchy(scriptRef.get().getName(), null, scriptRef, List.of())); + } + + return condenseHierarchy(hierarchy); } - private static ScriptHierarchy buildHierarchy( - DataStoreEntryRef ref, Predicate> include) { - if (ref.getStore() instanceof ScriptGroupStore) { - var directChildren = DataStorage.get().getStoreChildren(ref.get()).stream() - .filter(entry -> entry.getValidity().isUsable() && entry.getStore() instanceof ScriptStore) - .map(dataStoreEntry -> dataStoreEntry.ref()) - .toList(); - var children = directChildren.stream() - .filter(include) - .map(c -> buildHierarchy(c, include)) - .filter(hierarchy -> hierarchy.show()) - .sorted(Comparator.comparing(scriptHierarchy -> - scriptHierarchy.getBase().get().getName().toLowerCase())) - .toList(); - return new ScriptHierarchy(ref, children); - } else { - return new ScriptHierarchy(ref, List.of()); + private static Optional findParent(ScriptHierarchy hierarchy, DataStoreCategory category) { + if (category.equals(hierarchy.getCategory())) { + return Optional.of(hierarchy); } + + if (hierarchy.getChildren().stream().anyMatch(child -> category.equals(child.getCategory()))) { + return Optional.of(hierarchy); + } + + var children = hierarchy.getChildren(); + for (ScriptHierarchy child : children) { + var foundInChild = findParent(child, category); + if (foundInChild.isPresent()) { + return foundInChild; + } + } + + return Optional.empty(); } public static ScriptHierarchy condenseHierarchy(ScriptHierarchy hierarchy) { @@ -83,9 +110,9 @@ public class ScriptHierarchy { hierarchy.getChildren().stream().map(c -> condenseHierarchy(c)).toList(); if (children.size() == 1 && !children.getFirst().isLeaf()) { var nestedChildren = children.getFirst().getChildren(); - return new ScriptHierarchy(hierarchy.getBase(), nestedChildren); + return new ScriptHierarchy(children.getFirst().getName(), hierarchy.getCategory(), hierarchy.getScript(), nestedChildren); } else { - return new ScriptHierarchy(hierarchy.getBase(), children); + return new ScriptHierarchy(hierarchy.getName(), hierarchy.getCategory(), hierarchy.getScript(), children); } } @@ -94,14 +121,14 @@ public class ScriptHierarchy { } public boolean isEmptyBranch() { - return (base == null || base.getStore() instanceof ScriptGroupStore) && children.isEmpty(); + if (category == null) { + return false; + } + + return children.isEmpty(); } public boolean isLeaf() { - return base != null && base.getStore() instanceof ScriptStore && children.isEmpty(); - } - - public DataStoreEntryRef getLeafBase() { - return base.asNeeded(); + return script != null; } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java index f45eeecce..e4ca6e9e6 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java @@ -29,7 +29,6 @@ import java.util.SequencedCollection; @JsonTypeName("script") public class ScriptStore implements SelfReferentialStore, StatefulDataStore { - DataStoreEntryRef group; @Singular List> scripts; String description; @@ -99,8 +98,6 @@ public class ScriptStore implements SelfReferentialStore, StatefulDataStore { + EnabledStoreState s = sec.getWrapper().getEntry().getStorePersistentState(); + enabled.set(s.isEnabled()); + }); + + var toggle = StoreToggleComp.>enableToggle( + null, sec, enabled, (s, aBoolean) -> { + var state = s.getState().toBuilder().enabled(aBoolean).build(); + s.setState(state); + }); + + return StoreEntryComp.create(sec, toggle, preferLarge); + } @Override public DocumentationLink getHelpLink() { @@ -60,19 +84,12 @@ public class ScriptStoreProvider implements EnabledParentStoreProvider, DataStor return DataStoreCreationCategory.SCRIPT; } - @Override - public DataStoreEntry getDisplayParent(DataStoreEntry store) { - ScriptStore st = store.getStore().asNeeded(); - return st.getGroup().get(); - } - @SneakyThrows @Override public GuiDialog guiDialog(DataStoreEntry entry, Property store) { ScriptStore st = store.getValue().asNeeded(); var textSource = new SimpleObjectProperty<>(st.getTextSource()); - var group = new SimpleObjectProperty<>(st.getGroup()); var others = new SimpleListProperty<>(FXCollections.observableArrayList(new ArrayList<>(st.getEffectiveScripts()))); var textSourceChoice = OptionsChoiceBuilder.builder().property(textSource).available(ScriptTextSource.getClasses()).build(); @@ -137,23 +154,10 @@ public class ScriptStoreProvider implements EnabledParentStoreProvider, DataStor scriptStore -> !scriptStore.get().equals(entry) && !others.contains(scriptStore), StoreViewState.get().getAllScriptsCategory()), others) - .name("scriptGroup") - .description("scriptGroupDescription") - .documentationLink(DocumentationLink.SCRIPTING_GROUPS) - .addComp( - new StoreChoiceComp<>( - null, - group, - ScriptGroupStore.class, - null, - StoreViewState.get().getAllScriptsCategory()), - group) - .nonNull() .bind( () -> { return ScriptStore.builder() .textSource(textSource.get()) - .group(group.get()) .scripts(new ArrayList<>(others.get())) .description(st.getDescription()) .initScript(selectedExecTypes.contains(0)) diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java index 4d0c8f73f..64ffb68ba 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStoreSetup.java @@ -4,6 +4,8 @@ import io.xpipe.app.ext.StatefulDataStore; import io.xpipe.app.issue.ErrorEventFactory; import io.xpipe.app.process.*; import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.storage.DataStoreCategory; +import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; import io.xpipe.core.FilePath; import lombok.SneakyThrows; @@ -159,31 +161,16 @@ public class ScriptStoreSetup { return targetDir; } - public static Set> getEnabledScripts() { - var l = new HashSet>(); - DataStorage.get().getStoreEntries().stream() + public static List> getEnabledScripts() { + var l = DataStorage.get().getStoreEntries().stream() .filter(dataStoreEntry -> dataStoreEntry.getValidity().isUsable() - && dataStoreEntry.getStore() instanceof ScriptGroupStore g - && g.getParent() == null) - .forEach(e -> addGroupChildren(e.ref(), l)); + && dataStoreEntry.getStore() instanceof ScriptStore ss + && ss.getState().isEnabled()) + .>map(DataStoreEntry::ref) + .toList(); return l; } - private static void addGroupChildren(DataStoreEntryRef group, Set> l) { - var children = DataStorage.get().getStoreChildren(group.get()); - if (group.getStore().getState().isEnabled()) { - children.stream() - .filter(dataStoreEntry -> dataStoreEntry.getValidity().isUsable() - && dataStoreEntry.getStore() instanceof ScriptStore) - .forEach(e -> l.add(e.ref())); - } - - children.stream() - .filter(dataStoreEntry -> dataStoreEntry.getValidity().isUsable() - && dataStoreEntry.getStore() instanceof ScriptGroupStore) - .forEach(e -> addGroupChildren(e.ref(), l)); - } - public static List> flatten(Collection> scripts) { var seen = new LinkedHashSet>(); scripts.stream() diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index 7f8200f64..ad834bb54 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -62,8 +62,7 @@ open module io.xpipe.ext.base { LocalIdentityStoreProvider, SyncedIdentityStoreProvider, PasswordManagerIdentityStoreProvider, - AbstractHostStoreProvider, - ScriptGroupStoreProvider; + AbstractHostStoreProvider; provides DataStorageExtensionProvider with ScriptDataStorageProvider; }