mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-24 17:35:39 +00:00
Rework
This commit is contained in:
@@ -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.<StatefulDataStore<EnabledStoreState>>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);
|
||||
}
|
||||
}
|
||||
@@ -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<ScriptGroupStore> entry;
|
||||
|
||||
PredefinedScriptGroup(String name, String description, boolean expanded) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.expanded = expanded;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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<String> getName(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
|
||||
var b = hierarchy.getBase();
|
||||
return new SimpleStringProperty(b != null ? b.get().getName() : null);
|
||||
return new SimpleStringProperty(hierarchy.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<ShellStore
|
||||
public AbstractAction createAction(DataStoreEntryRef<ShellStore> ref) {
|
||||
return RunTerminalScriptActionProvider.Action.builder()
|
||||
.ref(ref)
|
||||
.scriptStore(hierarchy.getLeafBase())
|
||||
.scriptStore(hierarchy.getScript())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -214,7 +215,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider<ShellStore
|
||||
public RunTerminalScriptActionProvider.Action createBatchAction(DataStoreEntryRef<ShellStore> ref) {
|
||||
return RunTerminalScriptActionProvider.Action.builder()
|
||||
.ref(ref)
|
||||
.scriptStore(hierarchy.getLeafBase())
|
||||
.scriptStore(hierarchy.getScript())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -228,7 +229,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider<ShellStore
|
||||
public AbstractAction createAction(DataStoreEntryRef<ShellStore> ref) {
|
||||
return RunHubScriptActionProvider.Action.builder()
|
||||
.ref(ref)
|
||||
.scriptStore(hierarchy.getLeafBase())
|
||||
.scriptStore(hierarchy.getScript())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -266,7 +267,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider<ShellStore
|
||||
public AbstractAction createBatchAction(List<DataStoreEntryRef<ShellStore>> stores) {
|
||||
return RunHubBatchScriptActionProvider.Action.builder()
|
||||
.refs(stores)
|
||||
.scriptStore(hierarchy.getLeafBase())
|
||||
.scriptStore(hierarchy.getScript())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -274,7 +275,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider<ShellStore
|
||||
public RunHubScriptActionProvider.Action createBatchAction(DataStoreEntryRef<ShellStore> ref) {
|
||||
return RunHubScriptActionProvider.Action.builder()
|
||||
.ref(ref)
|
||||
.scriptStore(hierarchy.getLeafBase())
|
||||
.scriptStore(hierarchy.getScript())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -289,7 +290,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider<ShellStore
|
||||
public AbstractAction createAction(DataStoreEntryRef<ShellStore> ref) {
|
||||
return RunBackgroundScriptActionProvider.Action.builder()
|
||||
.ref(ref)
|
||||
.scriptStore(hierarchy.getLeafBase())
|
||||
.scriptStore(hierarchy.getScript())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -327,7 +328,7 @@ public class RunScriptActionProviderMenu implements HubBranchProvider<ShellStore
|
||||
public RunBackgroundScriptActionProvider.Action createBatchAction(DataStoreEntryRef<ShellStore> ref) {
|
||||
return RunBackgroundScriptActionProvider.Action.builder()
|
||||
.ref(ref)
|
||||
.scriptStore(hierarchy.getLeafBase())
|
||||
.scriptStore(hierarchy.getScript())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -344,16 +345,16 @@ public class RunScriptActionProviderMenu implements HubBranchProvider<ShellStore
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> 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
|
||||
|
||||
+10
-36
@@ -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<DataStoreEntryRef<ScriptGroupStore>> targetGroup = new SimpleObjectProperty<>();
|
||||
private final ObjectProperty<StoreCategoryWrapper> targetCategory = new SimpleObjectProperty<>();
|
||||
|
||||
public ScriptCollectionSourceImportDialog(DataStoreEntryRef<ScriptCollectionSourceStore> 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<DataStoreEntry>();
|
||||
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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<ScriptGroupStore>, SelfReferentialStore, StatefulDataStore<EnabledStoreState> {
|
||||
|
||||
DataStoreEntryRef<ScriptGroupStore> group;
|
||||
|
||||
String description;
|
||||
|
||||
@Override
|
||||
public Class<EnabledStoreState> getStateClass() {
|
||||
return EnabledStoreState.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkComplete() throws Throwable {
|
||||
if (group != null) {
|
||||
Validators.isType(group, ScriptGroupStore.class);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public DataStoreEntryRef<ScriptGroupStore> getParent() {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
@@ -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<DataStore> 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<String> 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<Class<?>> getStoreClasses() {
|
||||
return List.of(ScriptGroupStore.class);
|
||||
}
|
||||
}
|
||||
@@ -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<ScriptStore> script;
|
||||
List<ScriptHierarchy> children;
|
||||
|
||||
public static ScriptHierarchy buildEnabledHierarchy(Predicate<DataStoreEntryRef<ScriptStore>> include) {
|
||||
var enabled = ScriptStoreSetup.getEnabledScripts();
|
||||
var all = new HashSet<DataStoreEntryRef<?>>(ScriptStoreSetup.getEnabledScripts());
|
||||
var enabled = ScriptStoreSetup.getEnabledScripts().stream().filter(include).toList();
|
||||
|
||||
// Add parents
|
||||
var categories = new HashSet<DataStoreCategory>();
|
||||
for (DataStoreEntryRef<ScriptStore> ref : enabled) {
|
||||
DataStoreEntryRef<?> current = ref;
|
||||
while (true) {
|
||||
var parent = DataStorage.get().getDefaultDisplayParent(current.get());
|
||||
if (parent.isPresent()) {
|
||||
DataStoreEntryRef<ScriptGroupStore> 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<ScriptStore> 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<DataStoreEntryRef<ScriptStore>> 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.<ScriptStore>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<ScriptHierarchy> 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<ScriptStore> getLeafBase() {
|
||||
return base.asNeeded();
|
||||
return script != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.SequencedCollection;
|
||||
@JsonTypeName("script")
|
||||
public class ScriptStore implements SelfReferentialStore, StatefulDataStore<EnabledStoreState> {
|
||||
|
||||
DataStoreEntryRef<ScriptGroupStore> group;
|
||||
@Singular
|
||||
List<DataStoreEntryRef<ScriptStore>> scripts;
|
||||
String description;
|
||||
@@ -99,8 +98,6 @@ public class ScriptStore implements SelfReferentialStore, StatefulDataStore<Enab
|
||||
public void checkComplete() throws Throwable {
|
||||
Validators.nonNull(textSource);
|
||||
textSource.checkComplete();
|
||||
Validators.nonNull(group);
|
||||
Validators.isType(group, ScriptGroupStore.class);
|
||||
if (!initScript && !shellScript && !fileScript && !runnableScript) {
|
||||
throw new ValidationException(AppI18n.get("valueMustNotBeEmpty"));
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ import io.xpipe.app.comp.base.ListSelectorComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.*;
|
||||
import io.xpipe.app.hub.comp.*;
|
||||
import io.xpipe.app.platform.BindingsHelper;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.platform.OptionsChoiceBuilder;
|
||||
import io.xpipe.app.platform.Validator;
|
||||
import io.xpipe.app.process.OsFileSystem;
|
||||
import io.xpipe.app.process.ShellDialects;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreCategory;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.util.*;
|
||||
@@ -28,7 +30,29 @@ import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ScriptStoreProvider implements EnabledParentStoreProvider, DataStoreProvider {
|
||||
public class ScriptStoreProvider implements DataStoreProvider {
|
||||
|
||||
@Override
|
||||
public 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.<StatefulDataStore<EnabledStoreState>>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<DataStore> 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))
|
||||
|
||||
@@ -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<DataStoreEntryRef<ScriptStore>> getEnabledScripts() {
|
||||
var l = new HashSet<DataStoreEntryRef<ScriptStore>>();
|
||||
DataStorage.get().getStoreEntries().stream()
|
||||
public static List<DataStoreEntryRef<ScriptStore>> 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())
|
||||
.<DataStoreEntryRef<ScriptStore>>map(DataStoreEntry::ref)
|
||||
.toList();
|
||||
return l;
|
||||
}
|
||||
|
||||
private static void addGroupChildren(DataStoreEntryRef<ScriptGroupStore> group, Set<DataStoreEntryRef<ScriptStore>> 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<DataStoreEntryRef<ScriptStore>> flatten(Collection<DataStoreEntryRef<ScriptStore>> scripts) {
|
||||
var seen = new LinkedHashSet<DataStoreEntryRef<ScriptStore>>();
|
||||
scripts.stream()
|
||||
|
||||
@@ -62,8 +62,7 @@ open module io.xpipe.ext.base {
|
||||
LocalIdentityStoreProvider,
|
||||
SyncedIdentityStoreProvider,
|
||||
PasswordManagerIdentityStoreProvider,
|
||||
AbstractHostStoreProvider,
|
||||
ScriptGroupStoreProvider;
|
||||
AbstractHostStoreProvider;
|
||||
provides DataStorageExtensionProvider with
|
||||
ScriptDataStorageProvider;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user