mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-04-22 15:40:31 -04:00
Rework
This commit is contained in:
@@ -23,6 +23,7 @@ import lombok.Getter;
|
||||
import org.int4.fx.builders.common.AbstractRegionBuilder;
|
||||
import io.xpipe.app.comp.BaseRegionBuilder;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class AppDialog {
|
||||
@@ -30,6 +31,14 @@ public class AppDialog {
|
||||
@Getter
|
||||
private static final ObservableList<ModalOverlay> modalOverlays = FXCollections.observableArrayList();
|
||||
|
||||
public static Optional<ModalOverlay> getCurrentModalOverlay() {
|
||||
if (modalOverlays.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(modalOverlays.getLast());
|
||||
}
|
||||
|
||||
public static void closeDialog(ModalOverlay overlay) {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
synchronized (modalOverlays) {
|
||||
|
||||
@@ -65,7 +65,11 @@ public class StoreCategoryComp extends SimpleRegionBuilder {
|
||||
category.getName().setValue(newValue);
|
||||
}
|
||||
});
|
||||
var name = new LazyTextFieldComp(prop).style("name").build();
|
||||
var name = new LazyTextFieldComp(prop).style("name").apply(sp -> {
|
||||
category.getRenameTrigger().onFire(() -> {
|
||||
sp.requestFocus();
|
||||
});
|
||||
}).build();
|
||||
var showing = new SimpleBooleanProperty();
|
||||
|
||||
var expandIcon = Bindings.createObjectBinding(
|
||||
@@ -121,7 +125,7 @@ public class StoreCategoryComp extends SimpleRegionBuilder {
|
||||
})
|
||||
.apply(new ContextMenuAugment<>(
|
||||
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, null, () -> {
|
||||
var cm = createContextMenu(name);
|
||||
var cm = createContextMenu();
|
||||
showing.bind(cm.showingProperty());
|
||||
return cm;
|
||||
}))
|
||||
@@ -158,7 +162,7 @@ public class StoreCategoryComp extends SimpleRegionBuilder {
|
||||
categoryButton.apply(new ContextMenuAugment<>(
|
||||
mouseEvent -> mouseEvent.getButton() == MouseButton.SECONDARY,
|
||||
keyEvent -> keyEvent.getCode() == KeyCode.SPACE,
|
||||
() -> createContextMenu(name)));
|
||||
() -> createContextMenu()));
|
||||
categoryButton.apply(struc -> {
|
||||
struc.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (event.getCode() == KeyCode.SPACE) {
|
||||
@@ -200,7 +204,7 @@ public class StoreCategoryComp extends SimpleRegionBuilder {
|
||||
return v.build();
|
||||
}
|
||||
|
||||
private ContextMenu createContextMenu(Region text) {
|
||||
private ContextMenu createContextMenu() {
|
||||
var contextMenu = MenuHelper.createContextMenu();
|
||||
|
||||
if (AppPrefs.get().enableHttpApi().get()) {
|
||||
@@ -219,9 +223,7 @@ public class StoreCategoryComp extends SimpleRegionBuilder {
|
||||
|
||||
var newCategory = new MenuItem(AppI18n.get("createNewCategory"), new FontIcon("mdi2p-plus-thick"));
|
||||
newCategory.setOnAction(event -> {
|
||||
DataStorage.get()
|
||||
.addStoreCategory(
|
||||
DataStoreCategory.createNew(category.getCategory().getUuid(), AppI18n.get("newCategory")));
|
||||
StoreViewState.get().createNewCategory(category);
|
||||
});
|
||||
contextMenu.getItems().add(newCategory);
|
||||
|
||||
@@ -235,8 +237,8 @@ public class StoreCategoryComp extends SimpleRegionBuilder {
|
||||
|
||||
var rename = new MenuItem(AppI18n.get("rename"), new FontIcon("mdal-edit"));
|
||||
rename.setOnAction(event -> {
|
||||
text.setDisable(false);
|
||||
text.requestFocus();
|
||||
category.getRenameTrigger().fire(null);
|
||||
event.consume();
|
||||
});
|
||||
contextMenu.getItems().add(rename);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableStringValue;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.int4.fx.values.util.Trigger;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
@@ -35,6 +36,7 @@ public class StoreCategoryWrapper {
|
||||
private final BooleanProperty expanded = new SimpleBooleanProperty();
|
||||
private final Property<DataStoreColor> color = new SimpleObjectProperty<>();
|
||||
private final BooleanProperty largeCategoryOptimizations = new SimpleBooleanProperty();
|
||||
private final Trigger<Void> renameTrigger = Trigger.of();
|
||||
private StoreCategoryWrapper cachedParent;
|
||||
|
||||
public StoreCategoryWrapper(DataStoreCategory category) {
|
||||
|
||||
@@ -166,6 +166,7 @@ public class StoreChoiceComp<T extends DataStore> extends SimpleRegionBuilder {
|
||||
AnchorPane.setBottomAnchor(struc, 3.0);
|
||||
});
|
||||
pane.getChildren().add(clearButton.build());
|
||||
pane.getStyleClass().add("store-choice-comp");
|
||||
|
||||
return pane;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.xpipe.app.hub.comp;
|
||||
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.mode.AppOperationMode;
|
||||
import io.xpipe.app.ext.DataStoreUsageCategory;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
@@ -12,6 +13,7 @@ import io.xpipe.app.storage.DataStoreCategory;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.StorageListener;
|
||||
|
||||
import io.xpipe.app.util.GlobalTimer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
@@ -23,6 +25,7 @@ import javafx.collections.ListChangeListener;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -344,6 +347,18 @@ public class StoreViewState {
|
||||
});
|
||||
}
|
||||
|
||||
public void createNewCategory(StoreCategoryWrapper parent) {
|
||||
var cat = DataStoreCategory.createNew(parent.getCategory().getUuid(), AppI18n.get("newCategory"));
|
||||
DataStorage.get().addStoreCategory(cat);
|
||||
// Ugly solution to ensure that the category is added to the scene
|
||||
GlobalTimer.delay(() -> {
|
||||
var wrapper = getCategoryWrapper(cat);
|
||||
Platform.runLater(() -> {
|
||||
wrapper.getRenameTrigger().fire(null);
|
||||
});
|
||||
}, Duration.ofMillis(500));
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
if (AppPrefs.get() != null) {
|
||||
AppPrefs.get().condenseConnectionDisplay().addListener((observable, oldValue, newValue) -> {
|
||||
|
||||
@@ -11,6 +11,10 @@ public class ShellScript {
|
||||
|
||||
String value;
|
||||
|
||||
public static ShellScript empty() {
|
||||
return new ShellScript("");
|
||||
}
|
||||
|
||||
public static ShellScript of(String s) {
|
||||
return s != null ? new ShellScript(s) : null;
|
||||
}
|
||||
|
||||
@@ -208,15 +208,6 @@ public abstract class DataStorage {
|
||||
localIdentities.get().setParentCategory(ALL_IDENTITIES_CATEGORY_UUID);
|
||||
}
|
||||
|
||||
// var allMacros = getStoreCategoryIfPresent(ALL_MACROS_CATEGORY_UUID);
|
||||
// if (allMacros.isEmpty()) {
|
||||
// var cat = DataStoreCategory.createNew(null, ALL_MACROS_CATEGORY_UUID, "All macros");
|
||||
// cat.setDirectory(categoriesDir.resolve(ALL_MACROS_CATEGORY_UUID.toString()));
|
||||
// storeCategories.add(cat);
|
||||
// } else {
|
||||
// allMacros.get().setParentCategory(null);
|
||||
// }
|
||||
|
||||
if (supportsSync()) {
|
||||
var sharedIdentities = getStoreCategoryIfPresent(SYNCED_IDENTITIES_CATEGORY_UUID);
|
||||
if (sharedIdentities.isEmpty()) {
|
||||
@@ -230,17 +221,13 @@ public abstract class DataStorage {
|
||||
}
|
||||
}
|
||||
|
||||
if (getStoreCategoryIfPresent(DEFAULT_CATEGORY_UUID).isEmpty()) {
|
||||
storeCategories.add(new DataStoreCategory(
|
||||
categoriesDir.resolve(DEFAULT_CATEGORY_UUID.toString()),
|
||||
DEFAULT_CATEGORY_UUID,
|
||||
"Default",
|
||||
Instant.now(),
|
||||
Instant.now(),
|
||||
true,
|
||||
ALL_CONNECTIONS_CATEGORY_UUID,
|
||||
true,
|
||||
DataStoreCategoryConfig.empty()));
|
||||
var def = getStoreCategoryIfPresent(DEFAULT_CATEGORY_UUID);
|
||||
if (def.isEmpty()) {
|
||||
DataStoreCategory cat = new DataStoreCategory(categoriesDir.resolve(DEFAULT_CATEGORY_UUID.toString()), DEFAULT_CATEGORY_UUID,
|
||||
"Default", Instant.now(), Instant.now(), true, ALL_CONNECTIONS_CATEGORY_UUID, true, DataStoreCategoryConfig.empty());
|
||||
storeCategories.add(cat);
|
||||
} else {
|
||||
def.get().setParentCategory(ALL_CONNECTIONS_CATEGORY_UUID);
|
||||
}
|
||||
|
||||
storeCategories.forEach(dataStoreCategory -> {
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
-fx-icon-color: -color-fg-default;
|
||||
}
|
||||
|
||||
.store-choice-comp.left-pill .choice-comp {
|
||||
-fx-background-radius: 4 0 0 4;
|
||||
-fx-border-radius: 4 0 0 4;
|
||||
}
|
||||
|
||||
.choice-comp-content > .top {
|
||||
-fx-padding: 0.4em;
|
||||
-fx-background-color: -color-neutral-subtle;
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.UUID;
|
||||
|
||||
public class ScriptCollectionSourceImportDialog {
|
||||
|
||||
private final ScriptCollectionSource source;
|
||||
private final DataStoreEntryRef<ScriptCollectionSourceStore> source;
|
||||
private final ObservableList<ScriptCollectionSourceEntry> available = FXCollections.observableArrayList();
|
||||
private final ObservableList<ScriptCollectionSourceEntry> shown = FXCollections.observableArrayList();
|
||||
private final ObservableList<ScriptCollectionSourceEntry> selected = FXCollections.observableArrayList();
|
||||
@@ -45,9 +45,9 @@ public class ScriptCollectionSourceImportDialog {
|
||||
private final IntegerProperty count = new SimpleIntegerProperty();
|
||||
private final ObjectProperty<DataStoreEntryRef<ScriptGroupStore>> targetGroup = new SimpleObjectProperty<>();
|
||||
|
||||
public ScriptCollectionSourceImportDialog(ScriptCollectionSource source) {
|
||||
public ScriptCollectionSourceImportDialog(DataStoreEntryRef<ScriptCollectionSourceStore> source) {
|
||||
this.source = source;
|
||||
available.setAll(source.listScripts());
|
||||
available.setAll(source.getStore().getSource().listScripts());
|
||||
update();
|
||||
|
||||
filter.addListener((observable, oldValue, newValue) -> {
|
||||
@@ -74,8 +74,8 @@ public class ScriptCollectionSourceImportDialog {
|
||||
var refresh = new ButtonComp(null, new FontIcon("mdmz-refresh"), () -> {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try (var ignored = new BooleanScope(busy).exclusive().start()) {
|
||||
source.prepare();
|
||||
var all = source.listScripts();
|
||||
source.getStore().getSource().prepare();
|
||||
var all = source.getStore().getSource().listScripts();
|
||||
available.setAll(all);
|
||||
update();
|
||||
} catch (Exception e) {
|
||||
@@ -151,7 +151,7 @@ public class ScriptCollectionSourceImportDialog {
|
||||
var added = new ArrayList<DataStoreEntry>();
|
||||
for (ScriptCollectionSourceEntry e : selected) {
|
||||
var name = FilePath.of(e.getName()).getBaseName().toString();
|
||||
var textSource = ScriptTextSource.SourceReference.builder().entry(e).build();
|
||||
var textSource = ScriptTextSource.SourceReference.builder().ref(source).name(e.getName()).build();
|
||||
|
||||
var alreadyAdded = DataStorage.get().getStoreEntries().stream().anyMatch(entry -> entry.getStore() instanceof ScriptStore ss &&
|
||||
textSource.equals(ss.getTextSource()));
|
||||
|
||||
@@ -48,7 +48,7 @@ public class ScriptCollectionSourceImportHubProvider implements HubLeafProvider<
|
||||
|
||||
@Override
|
||||
public void executeImpl() {
|
||||
var dialog = new ScriptCollectionSourceImportDialog(ref.getStore().getSource());
|
||||
var dialog = new ScriptCollectionSourceImportDialog(ref);
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class ScriptCollectionSourceStore implements DataStore, StatefulDataStore
|
||||
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
source.prepare();
|
||||
refresh();
|
||||
}
|
||||
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.xpipe.app.util.Validators;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import lombok.Singular;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
@@ -75,9 +76,15 @@ public class ScriptStore implements SelfReferentialStore, StatefulDataStore<Enab
|
||||
return null;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String assembleScriptChain(ShellControl shellControl, boolean args) {
|
||||
var nl = shellControl.getShellDialect().getNewLine().getNewLineString();
|
||||
var all = queryFlattenedScripts();
|
||||
|
||||
for (DataStoreEntryRef<ScriptStore> ref : all) {
|
||||
ref.getStore().getTextSource().checkAvailable();
|
||||
}
|
||||
|
||||
var r = all.stream()
|
||||
.map(ref -> ref.getStore().assembleScript(shellControl, args))
|
||||
.filter(s -> s != null)
|
||||
@@ -91,6 +98,7 @@ public class ScriptStore implements SelfReferentialStore, StatefulDataStore<Enab
|
||||
@Override
|
||||
public void checkComplete() throws Throwable {
|
||||
Validators.nonNull(textSource);
|
||||
textSource.checkComplete();
|
||||
Validators.nonNull(group);
|
||||
Validators.isType(group, ScriptGroupStore.class);
|
||||
if (!initScript && !shellScript && !fileScript && !runnableScript) {
|
||||
|
||||
@@ -16,10 +16,7 @@ import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
|
||||
@@ -195,18 +192,10 @@ public class ScriptStoreProvider implements EnabledParentStoreProvider, DataStor
|
||||
var file = st.isFileScript() ? AppI18n.get("fileBrowser") : null;
|
||||
var shell = st.isShellScript() ? AppI18n.get("shell") : null;
|
||||
var runnable = st.isRunnableScript() ? AppI18n.get("hub") : null;
|
||||
var type = st.getMinimumDialect() != null
|
||||
? st.getMinimumDialect().getDisplayName() + " " + AppI18n.get("script")
|
||||
: AppI18n.get("genericScript");
|
||||
var suffix = String.join(
|
||||
" / ",
|
||||
Stream.of(init, shell, file, runnable).filter(s -> s != null).toList());
|
||||
if (!suffix.isEmpty()) {
|
||||
suffix = "(" + suffix + ")";
|
||||
} else {
|
||||
suffix = null;
|
||||
}
|
||||
return new SimpleStringProperty(DataStoreFormatter.join(type, suffix));
|
||||
var generic = st.getMinimumDialect() == null ? AppI18n.get("genericScript") : null;
|
||||
var dialect = st.getMinimumDialect() != null ? st.getMinimumDialect().getScriptFileEnding() : null;
|
||||
return new ReadOnlyObjectWrapper<>(new StoreStateFormat(
|
||||
List.of(), st.getTextSource().toSummary(), init, file, shell, runnable, generic, dialect).format());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.xpipe.app.process.*;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.core.FilePath;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -101,6 +102,7 @@ public class ScriptStoreSetup {
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static FilePath initScriptsDirectory(ShellControl sc, List<DataStoreEntryRef<ScriptStore>> refs)
|
||||
throws Exception {
|
||||
if (refs.isEmpty()) {
|
||||
@@ -138,6 +140,10 @@ public class ScriptStoreSetup {
|
||||
}
|
||||
sc.view().mkdir(targetDir);
|
||||
|
||||
for (DataStoreEntryRef<ScriptStore> ref : refs) {
|
||||
ref.getStore().getTextSource().checkAvailable();
|
||||
}
|
||||
|
||||
var d = sc.getShellDialect();
|
||||
for (DataStoreEntryRef<ScriptStore> scriptStore : refs) {
|
||||
var src = scriptStore.getStore().getTextSource();
|
||||
|
||||
@@ -4,18 +4,21 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
|
||||
import io.xpipe.app.comp.base.ContextualFileReferenceChoiceComp;
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.comp.base.InputGroupComp;
|
||||
import io.xpipe.app.comp.base.IntegratedTextAreaComp;
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.core.window.AppDialog;
|
||||
import io.xpipe.app.ext.ShellDialectChoiceComp;
|
||||
import io.xpipe.app.ext.ValidationException;
|
||||
import io.xpipe.app.hub.comp.StoreChoiceComp;
|
||||
import io.xpipe.app.hub.comp.StoreViewState;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.platform.LabelGraphic;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.process.ShellDialect;
|
||||
import io.xpipe.app.process.ShellScript;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.DocumentationLink;
|
||||
import io.xpipe.app.util.HttpHelper;
|
||||
import io.xpipe.app.util.Validators;
|
||||
@@ -23,7 +26,6 @@ import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.UuidHelper;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import lombok.Builder;
|
||||
@@ -33,10 +35,9 @@ import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
@@ -45,8 +46,8 @@ import java.util.List;
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = ScriptTextSource.InPlace.class),
|
||||
@JsonSubTypes.Type(value = ScriptTextSource.Url.class),
|
||||
@JsonSubTypes.Type(value = ScriptTextSource.SourceReference.class)
|
||||
@JsonSubTypes.Type(value = ScriptTextSource.SourceReference.class),
|
||||
@JsonSubTypes.Type(value = ScriptTextSource.Url.class)
|
||||
})
|
||||
public interface ScriptTextSource {
|
||||
|
||||
@@ -94,9 +95,12 @@ public interface ScriptTextSource {
|
||||
Validators.nonNull(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAvailable() throws Exception {}
|
||||
|
||||
@Override
|
||||
public String toSummary() {
|
||||
return dialect.getDisplayName();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +112,6 @@ public interface ScriptTextSource {
|
||||
|
||||
ShellDialect dialect;
|
||||
String url;
|
||||
ShellScript lastText;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static String getOptionsNameKey() {
|
||||
@@ -132,7 +135,7 @@ public interface ScriptTextSource {
|
||||
() -> Url.builder().dialect(dialect.get()).url(url.get()).build(), property);
|
||||
}
|
||||
|
||||
private void prepare() throws Exception {
|
||||
public void refresh() throws Exception {
|
||||
var path = getLocalPath();
|
||||
if (Files.exists(path)) {
|
||||
return;
|
||||
@@ -163,18 +166,31 @@ public interface ScriptTextSource {
|
||||
@Override
|
||||
public void checkComplete() throws ValidationException {
|
||||
Validators.nonNull(url);
|
||||
Validators.nonNull(lastText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAvailable() throws Exception {
|
||||
if (!Files.exists(getLocalPath())) {
|
||||
throw ErrorEventFactory.expected(new IllegalStateException("Script URL " + url + " has not been initialized"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toSummary() {
|
||||
return url;
|
||||
try {
|
||||
var uri = URI.create(url);
|
||||
return FilePath.of(uri.getPath()).getFileName();
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public ShellScript getText() {
|
||||
return lastText;
|
||||
var path = getLocalPath();
|
||||
var s = Files.readString(path);
|
||||
return ShellScript.of(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +200,8 @@ public interface ScriptTextSource {
|
||||
@Builder
|
||||
class SourceReference implements ScriptTextSource {
|
||||
|
||||
ScriptCollectionSourceEntry entry;
|
||||
DataStoreEntryRef<ScriptCollectionSourceStore> ref;
|
||||
String name;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static String getOptionsNameKey() {
|
||||
@@ -193,38 +210,96 @@ public interface ScriptTextSource {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static OptionsBuilder createOptions(Property<SourceReference> property) {
|
||||
var entry = new SimpleObjectProperty<>(property.getValue().getEntry());
|
||||
var ref = new SimpleObjectProperty<>(property.getValue().getRef());
|
||||
var name = new SimpleStringProperty(property.getValue().getName());
|
||||
|
||||
return new OptionsBuilder().bind(
|
||||
() -> SourceReference.builder().entry(entry.get()).build(), property);
|
||||
var sourceChoice = new StoreChoiceComp<>(null, ref, ScriptCollectionSourceStore.class,
|
||||
ignored -> true,
|
||||
StoreViewState.get().getAllScriptsCategory(),
|
||||
StoreViewState.get().getScriptSourcesCategory());
|
||||
|
||||
var importButton = new ButtonComp(null, new LabelGraphic.IconGraphic("mdi2i-import"), () -> {
|
||||
var current = AppDialog.getCurrentModalOverlay();
|
||||
current.ifPresent(modalOverlay -> modalOverlay.close());
|
||||
|
||||
var dialog = new ScriptCollectionSourceImportDialog(ref.get());
|
||||
dialog.show();
|
||||
});
|
||||
importButton.disable(ref.isNull());
|
||||
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("scriptCollectionSourceType")
|
||||
.addComp(new InputGroupComp(List.of(sourceChoice, importButton)).setMainReference(0), ref)
|
||||
.nonNull()
|
||||
.nameAndDescription("scriptSourceName")
|
||||
.addString(name)
|
||||
.nonNull()
|
||||
.bind(
|
||||
() -> SourceReference.builder().ref(ref.getValue()).name(name.getValue()).build(), property);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void checkComplete() throws ValidationException {
|
||||
Validators.nonNull(entry);
|
||||
entry.getSource().checkComplete();
|
||||
Validators.nonNull(ref);
|
||||
ref.checkComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAvailable() throws Exception {
|
||||
var cached = ref.getStore().getState().getEntries();
|
||||
if (cached == null) {
|
||||
throw ErrorEventFactory.expected(new IllegalStateException("Source " + ref.get().getName() + " has not been initialized"));
|
||||
}
|
||||
|
||||
var found = cached.stream().filter(e -> e.getName().equals(name)).findFirst().orElse(null);
|
||||
if (found == null) {
|
||||
throw ErrorEventFactory.expected(new IllegalStateException("Script " + name + " not found in local source " + ref.get().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toSummary() {
|
||||
return entry.getName();
|
||||
return ref.get().getName() + "/" + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellDialect getDialect() {
|
||||
return entry.getDialect();
|
||||
var found = findSourceEntryIfPossible();
|
||||
return found != null ? found.getDialect() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public ShellScript getText() {
|
||||
var r = Files.readString(entry.getLocalFile());
|
||||
var found = findSourceEntryIfPossible();
|
||||
if (found == null) {
|
||||
return ShellScript.empty();
|
||||
}
|
||||
|
||||
var r = Files.readString(found.getLocalFile());
|
||||
return ShellScript.of(r);
|
||||
}
|
||||
|
||||
private ScriptCollectionSourceEntry findSourceEntryIfPossible() {
|
||||
var cached = ref.getStore().getState().getEntries();
|
||||
if (cached == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var found = cached.stream().filter(e -> e.getName().equals(name)).findFirst().orElse(null);
|
||||
if (found == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
void checkComplete() throws ValidationException;
|
||||
|
||||
void checkAvailable() throws Exception;
|
||||
|
||||
String toSummary();
|
||||
|
||||
ShellDialect getDialect();
|
||||
@@ -234,8 +309,8 @@ public interface ScriptTextSource {
|
||||
static List<Class<?>> getClasses() {
|
||||
var l = new ArrayList<Class<?>>();
|
||||
l.add(InPlace.class);
|
||||
l.add(Url.class);
|
||||
l.add(SourceReference.class);
|
||||
l.add(Url.class);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.xpipe.ext.base.script;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.hub.action.HubLeafProvider;
|
||||
import io.xpipe.app.hub.action.StoreAction;
|
||||
import io.xpipe.app.hub.action.StoreActionCategory;
|
||||
import io.xpipe.app.platform.LabelGraphic;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
public class ScriptUrlSourceRefreshHubProvider implements HubLeafProvider<ScriptStore> {
|
||||
|
||||
@Override
|
||||
public StoreActionCategory getCategory() {
|
||||
return StoreActionCategory.CUSTOM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(DataStoreEntryRef<ScriptStore> o) {
|
||||
return o.getStore().getTextSource() instanceof ScriptTextSource.Url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMajor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<ScriptStore> store) {
|
||||
return AppI18n.observable("refreshSource");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LabelGraphic getIcon(DataStoreEntryRef<ScriptStore> store) {
|
||||
return new LabelGraphic.IconGraphic("mdi2r-refresh");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getApplicableClass() {
|
||||
return ScriptStore.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "refreshScriptUrlSource";
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
@SuperBuilder
|
||||
public static class Action extends StoreAction<ScriptStore> {
|
||||
|
||||
@Override
|
||||
public void executeImpl() throws Exception {
|
||||
var url = (ScriptTextSource.Url) ref.getStore().getTextSource();
|
||||
url.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ open module io.xpipe.ext.base {
|
||||
RunBackgroundScriptActionProvider,
|
||||
RunHubBatchScriptActionProvider,
|
||||
RunHubScriptActionProvider,
|
||||
RunTerminalScriptActionProvider, ScriptCollectionSourceImportHubProvider, ScriptCollectionSourceRefreshHubProvider, ScriptCollectionSourceBrowseActionProvider, ScriptQuickEditHubLeafProvider,
|
||||
RunTerminalScriptActionProvider, ScriptCollectionSourceImportHubProvider, ScriptUrlSourceRefreshHubProvider, ScriptCollectionSourceRefreshHubProvider, ScriptCollectionSourceBrowseActionProvider, ScriptQuickEditHubLeafProvider,
|
||||
StoreStartActionProvider,
|
||||
StoreStopActionProvider,
|
||||
StorePauseActionProvider,
|
||||
|
||||
14
lang/strings/translations_en.properties
generated
14
lang/strings/translations_en.properties
generated
@@ -679,7 +679,8 @@ scriptGroup.displayName=Script group
|
||||
scriptGroup.displayDescription=Group scripts together and organize them within
|
||||
scriptGroup=Group
|
||||
scriptGroupDescription=The group to assign this script to
|
||||
scriptGroupGroupDescription=The group to assign this script group to
|
||||
#force
|
||||
scriptGroupGroupDescription=The optional parent group to assign this script group to
|
||||
openInNewTab=Open in new tab
|
||||
executeInBackground=in background
|
||||
executeInTerminal=in $TERM$
|
||||
@@ -778,7 +779,8 @@ shell=Shell
|
||||
hub=Hub
|
||||
#context: Computer script
|
||||
script=script
|
||||
genericScript=Generic script
|
||||
#force
|
||||
genericScript=Generic
|
||||
archiveName=Archive name
|
||||
compress=Compress
|
||||
compressContents=Compress contents
|
||||
@@ -1922,9 +1924,9 @@ scriptTextSourceUrl=Script URL
|
||||
scriptTextSourceUrlDescription=The URL to retrieve the script file from
|
||||
scriptSourceType=Script source
|
||||
scriptSourceTypeDescription=From where to source the script
|
||||
scriptSourceTypeInPlace=In-place
|
||||
scriptSourceTypeUrl=URL
|
||||
scriptSourceTypeSource=Source
|
||||
scriptSourceTypeInPlace=In-place script
|
||||
scriptSourceTypeUrl=External URL
|
||||
scriptSourceTypeSource=Script collection source
|
||||
importScripts=Import scripts
|
||||
scriptsContained=$NUMBER$ scripts
|
||||
scriptSourceCollectionImportTitle=Import scripts from source ($COUNT$)
|
||||
@@ -1932,3 +1934,5 @@ noScriptsFound=No scripts found
|
||||
tunnel=Tunnel
|
||||
notInitialized=Not initialized
|
||||
selectCategory=Select category ...
|
||||
scriptSourceName=Script name
|
||||
scriptSourceNameDescription=The file name of the script in the source
|
||||
|
||||
Reference in New Issue
Block a user