This commit is contained in:
crschnick
2026-01-20 03:47:41 +00:00
parent 927fd99c79
commit 8a06fe4f72
11 changed files with 152 additions and 22 deletions
@@ -240,28 +240,24 @@ public class StoreCategoryComp extends SimpleComp {
contextMenu.getItems().add(new SeparatorMenuItem());
var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline"));
StoreViewState.get()
.getSortedCategories(getCategory().getRoot())
.getList()
.forEach(storeCategoryWrapper -> {
MenuItem m = new MenuItem();
m.textProperty()
.setValue(" ".repeat(storeCategoryWrapper.getDepth())
+ storeCategoryWrapper.getName().getValue());
m.setOnAction(event -> {
category.moveToParent(storeCategoryWrapper.getCategory());
event.consume();
});
if (storeCategoryWrapper.getParent() == null
|| storeCategoryWrapper.equals(category)
|| storeCategoryWrapper.equals(category.getParent())) {
m.setDisable(true);
}
move.getItems().add(m);
if (category.canMove()) {
var move = new Menu(AppI18n.get("moveTo"), new FontIcon("mdi2f-folder-move-outline"));
StoreViewState.get().getSortedCategories(getCategory().getRoot()).getList().forEach(storeCategoryWrapper -> {
MenuItem m = new MenuItem();
m.textProperty().setValue(" ".repeat(storeCategoryWrapper.getDepth()) + storeCategoryWrapper.getName().getValue());
m.setOnAction(event -> {
category.moveToParent(storeCategoryWrapper.getCategory());
event.consume();
});
contextMenu.getItems().add(move);
if (storeCategoryWrapper.getParent() == null || storeCategoryWrapper.equals(category) || storeCategoryWrapper.equals(
category.getParent())) {
m.setDisable(true);
}
move.getItems().add(m);
});
contextMenu.getItems().add(move);
}
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
del.setOnAction(event -> {
@@ -73,6 +73,10 @@ public class StoreCategoryWrapper {
nameProperty());
}
public boolean canMove() {
return DataStorage.get().canMoveStoreCategory(category);
}
public StoreCategoryWrapper getRoot() {
return StoreViewState.get().getCategoryWrapper(root);
}
@@ -121,6 +121,20 @@ public class StoreEntryListComp extends SimpleComp {
},
scriptsIntroShowing,
StoreViewState.get().getActiveCategory());
var showScriptSourcesIntro = Bindings.createBooleanBinding(
() -> {
var cat = StoreViewState.get().getScriptSourcesCategory();
if (StoreViewState.get()
.getActiveCategory()
.getValue()
.equals(cat)) {
return cat.getAllContainedEntriesCount().get() == 0;
}
return false;
},
StoreViewState.get().getAllEntries().getList(),
StoreViewState.get().getActiveCategory());
var showList = Bindings.createBooleanBinding(
() -> {
if (StoreViewState.get()
@@ -160,6 +174,7 @@ public class StoreEntryListComp extends SimpleComp {
map.put(createList(), showList);
map.put(new StoreIntroComp(), showIntro);
map.put(new StoreScriptsIntroComp(scriptsIntroShowing), showScriptsIntro);
map.put(new StoreScriptSourcesIntroComp(), showScriptSourcesIntro);
map.put(new StoreIdentitiesIntroComp(), showIdentitiesIntro);
return new MultiContentComp(false, map, false).createRegion();
@@ -0,0 +1,29 @@
package io.xpipe.app.hub.comp;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.IntroComp;
import io.xpipe.app.comp.base.IntroListComp;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.ext.DataStoreCreationCategory;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.platform.LabelGraphic;
import javafx.beans.property.BooleanProperty;
import javafx.scene.layout.Region;
import java.util.List;
public class StoreScriptSourcesIntroComp extends SimpleComp {
@Override
public Region createSimple() {
var intro = new IntroComp("scriptSourcesIntro", new LabelGraphic.IconGraphic("mdi2d-download"));
intro.setButtonGraphic(new LabelGraphic.IconGraphic("mdi2p-play-circle"));
intro.setButtonDefault(true);
intro.setButtonAction(() -> {
StoreCreationDialog.showCreation(DataStoreProviders.byId("scriptSource").orElseThrow(), DataStoreCreationCategory.SCRIPT);
});
var list = new IntroListComp(List.of(intro));
return list.createRegion();
}
}
@@ -616,6 +616,14 @@ public class StoreViewState {
.orElseThrow();
}
public StoreCategoryWrapper getScriptSourcesCategory() {
return categories.getList().stream()
.filter(storeCategoryWrapper ->
storeCategoryWrapper.getCategory().getUuid().equals(DataStorage.SCRIPT_SOURCES_CATEGORY_UUID))
.findFirst()
.orElseThrow();
}
public StoreCategoryWrapper getAllIdentitiesCategory() {
return categories.getList().stream()
.filter(storeCategoryWrapper ->
@@ -1008,6 +1008,10 @@ public abstract class DataStorage {
return true;
}
public boolean canMoveStoreCategory(@NonNull DataStoreCategory cat) {
return canDeleteStoreCategory(cat);
}
public void deleteStoreCategory(@NonNull DataStoreCategory cat, boolean deleteChildren, boolean deleteEntries) {
if (!canDeleteStoreCategory(cat)) {
return;
@@ -12,6 +12,7 @@ import io.xpipe.app.ext.ValidationException;
import io.xpipe.app.icon.SystemIconSource;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.platform.OptionsBuilder;
import io.xpipe.app.process.ShellDialects;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.util.Validators;
import io.xpipe.core.FilePath;
@@ -157,12 +158,20 @@ public interface ScriptSource {
String toName();
default List<ScriptSourceEntry> listScripts() throws Exception {
var availableDialects = List.of(
ShellDialects.SH,
ShellDialects.BASH,
ShellDialects.ZSH,
ShellDialects.FISH,
ShellDialects.CMD,
ShellDialects.POWERSHELL,
ShellDialects.POWERSHELL_CORE);
var l = new ArrayList<ScriptSourceEntry>();
Files.walkFileTree(getLocalPath(), new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
var name = file.getFileName().toString();
var dialect = ShellDialectChoiceComp.ICONS.keySet().stream().filter(shellDialect -> {
var dialect = availableDialects.stream().filter(shellDialect -> {
return name.endsWith("." + shellDialect.getScriptFileEnding());
}).findFirst();
if (dialect.isEmpty()) {
@@ -0,0 +1,59 @@
package io.xpipe.ext.base.script;
import io.xpipe.app.action.AbstractAction;
import io.xpipe.app.browser.BrowserFullSessionModel;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.FileSystemStore;
import io.xpipe.app.hub.action.HubLeafProvider;
import io.xpipe.app.hub.action.StoreAction;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.DesktopHelper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
public class ScriptSourceBrowseActionProvider implements HubLeafProvider<ScriptSourceStore> {
@Override
public AbstractAction createAction(DataStoreEntryRef<ScriptSourceStore> ref) {
return Action.builder().ref(ref).build();
}
@Override
public boolean isMajor() {
return true;
}
@Override
public ObservableValue<String> getName(DataStoreEntryRef<ScriptSourceStore> store) {
return AppI18n.observable("browse");
}
@Override
public LabelGraphic getIcon(DataStoreEntryRef<ScriptSourceStore> store) {
return new LabelGraphic.IconGraphic("mdi2f-folder-search-outline");
}
@Override
public Class<ScriptSourceStore> getApplicableClass() {
return ScriptSourceStore.class;
}
@Override
public String getId() {
return "browseScriptSource";
}
@Jacksonized
@SuperBuilder
public static class Action extends StoreAction<ScriptSourceStore> {
@Override
public void executeImpl() {
DesktopHelper.browseFile(ref.getStore().getSource().getLocalPath());
}
}
}
@@ -3,11 +3,13 @@ package io.xpipe.ext.base.script;
import io.xpipe.app.process.ShellDialect;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import java.nio.file.Path;
@Value
@Builder
@Jacksonized
public class ScriptSourceEntry {
String name;
+1
View File
@@ -44,6 +44,7 @@ open module io.xpipe.ext.base {
RunHubScriptActionProvider,
RunTerminalScriptActionProvider,
ScriptSourceRefreshHubProvider,
ScriptSourceBrowseActionProvider,
SimpleScriptQuickEditHubLeafProvider,
StoreStartActionProvider,
StoreStopActionProvider,
+3
View File
@@ -536,6 +536,9 @@ scriptsIntroBottomHeader=Using scripts
#force
scriptsIntroBottomContent=There are a variety of sample scripts to start out. You can click on the edit button of the individual scripts to see how they are implemented. Scripts first have to be enabled to run and show up in menus, there is a toggle on every script for that.
scriptsIntroBottomButton=Get started
scriptSourcesIntroHeader=Script sources
scriptSourcesIntroContent=You can add custom script sources to have instant access to an entire collection of shell scripts. Both local sources and remote git repositories are supported as sources. All detected scripts from the source will become available automatically.
scriptSourcesIntroButton=Add source ...
checkForSecurityUpdates=Check for security updates
checkForSecurityUpdatesDescription=XPipe can check for potential security updates separately from normal feature updates. When this is enabled, at least important security updates will be recommended for installation even if the normal update check is disabled.\n\nDisabling this setting will result in no external version request being performed, and you won't be notified about any security updates.
clickToDock=Click to dock terminal