This commit is contained in:
crschnick 2024-09-27 17:24:24 +00:00
parent f5e63fdf52
commit f810ce0f81
39 changed files with 180 additions and 108 deletions

View file

@ -20,7 +20,8 @@ import java.util.Objects;
public class BrowserFileOpener {
private static OutputStream openFileOutput(OpenFileSystemModel model, FileEntry file, long totalBytes) throws Exception {
private static OutputStream openFileOutput(OpenFileSystemModel model, FileEntry file, long totalBytes)
throws Exception {
var fileSystem = model.getFileSystem();
if (model.isClosed() || fileSystem.getShell().isEmpty()) {
return OutputStream.nullOutputStream();
@ -39,12 +40,15 @@ public class BrowserFileOpener {
return fileSystem.openOutput(file.getPath(), totalBytes);
}
var elevate = AppWindowHelper.showConfirmationAlert("app.fileWriteSudoTitle", "app.fileWriteSudoHeader", "app.fileWriteSudoContent");
var elevate = AppWindowHelper.showConfirmationAlert(
"app.fileWriteSudoTitle", "app.fileWriteSudoHeader", "app.fileWriteSudoContent");
if (!elevate) {
return fileSystem.openOutput(file.getPath(), totalBytes);
}
var rootSc = sc.identicalSubShell().elevated(ElevationFunction.elevated("sudo")).start();
var rootSc = sc.identicalSubShell()
.elevated(ElevationFunction.elevated("sudo"))
.start();
var rootFs = new ConnectionFileSystem(rootSc);
try {
return new FilterOutputStream(rootFs.openOutput(file.getPath(), totalBytes)) {
@ -123,7 +127,7 @@ public class BrowserFileOpener {
return entry.getFileSystem().openInput(file);
},
(size) -> {
return openFileOutput(model,entry, size);
return openFileOutput(model, entry, size);
},
FileOpener::openInTextEditor);
}

View file

@ -142,8 +142,7 @@ public class BrowserQuickAccessContextMenu extends ContextMenu {
this.menu = new Menu(
// Use original name, not the link target
browserEntry.getRawFileEntry().getName(),
PrettyImageHelper.ofFixedSize(
FileIconManager.getFileIcon(browserEntry.getRawFileEntry()), 24, 24)
PrettyImageHelper.ofFixedSize(FileIconManager.getFileIcon(browserEntry.getRawFileEntry()), 24, 24)
.createRegion());
createMenu();
addInputListeners();

View file

@ -25,8 +25,10 @@ import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.process.ShellOpenFunction;
import io.xpipe.core.store.*;
import io.xpipe.core.util.FailableConsumer;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import lombok.Getter;
import lombok.SneakyThrows;
@ -71,7 +73,9 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
@Override
public boolean canImmediatelyClose() {
if (fileSystem == null || fileSystem.getShell().isEmpty() || !fileSystem.getShell().get().getLock().isLocked()) {
if (fileSystem == null
|| fileSystem.getShell().isEmpty()
|| !fileSystem.getShell().get().getLock().isLocked()) {
return true;
}
@ -251,7 +255,11 @@ public final class OpenFileSystemModel extends BrowserSessionTab<FileSystemStore
entry.getEntry(),
name,
directory,
fileSystem.getShell().get().singularSubShell(ShellOpenFunction.of(CommandBuilder.ofString(adjustedPath), false)));
fileSystem
.getShell()
.get()
.singularSubShell(
ShellOpenFunction.of(CommandBuilder.ofString(adjustedPath), false)));
} else {
TerminalLauncher.open(
entry.getEntry(),

View file

@ -63,10 +63,7 @@ public abstract class BrowserIconDirectoryType {
var closedIcon = "browser/" + split[2].trim();
var lightClosedIcon = split.length > 4 ? "browser/" + split[4].trim() : closedIcon;
ALL.add(new Simple(
id,
new IconVariant(lightClosedIcon, closedIcon),
filter));
ALL.add(new Simple(id, new IconVariant(lightClosedIcon, closedIcon), filter));
}
}
});

View file

@ -35,8 +35,6 @@ public class FileIconManager {
}
}
return "browser/" + (r.getKind() == FileKind.DIRECTORY
? "default_folder.svg"
: "default_file.svg");
return "browser/" + (r.getKind() == FileKind.DIRECTORY ? "default_folder.svg" : "default_file.svg");
}
}

View file

@ -20,6 +20,7 @@ import io.xpipe.app.util.FileReference;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.store.FileSystemStore;
import io.xpipe.core.store.ShellStore;
import javafx.beans.property.BooleanProperty;
import javafx.collections.ListChangeListener;
import javafx.geometry.Pos;
@ -64,10 +65,6 @@ public class BrowserChooserComp extends DialogComp {
});
}
@Override
protected String finishKey() {
return "select";

View file

@ -329,11 +329,14 @@ public class BrowserSessionTabsComp extends SimpleComp {
ring.setMaxSize(16, 16);
ring.progressProperty()
.bind(Bindings.createDoubleBinding(
() -> model.getBusy().get() && !AppPrefs.get().performanceMode().get() ? -1d : 0, PlatformThread.sync(model.getBusy()), AppPrefs.get().performanceMode()));
() -> model.getBusy().get()
&& !AppPrefs.get().performanceMode().get()
? -1d
: 0,
PlatformThread.sync(model.getBusy()),
AppPrefs.get().performanceMode()));
var image = model.getEntry()
.get()
.getEffectiveIconFile();
var image = model.getEntry().get().getEffectiveIconFile();
var logo = PrettyImageHelper.ofFixedSizeSquare(image, 16).createRegion();
tab.graphicProperty()

View file

@ -8,6 +8,7 @@ import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.resources.AppResources;
import io.xpipe.core.process.OsNameState;
import io.xpipe.core.store.FileNames;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
@ -52,8 +53,9 @@ public class OsLogoComp extends SimpleComp {
wrapper.getPersistentState(),
state);
var hide = BindingsHelper.map(img, s -> s != null);
return new StackComp(
List.of(new SystemStateComp(state).hide(hide), PrettyImageHelper.ofFixedSize(img, 24, 24).visible(hide)))
return new StackComp(List.of(
new SystemStateComp(state).hide(hide),
PrettyImageHelper.ofFixedSize(img, 24, 24).visible(hide)))
.createRegion();
}
@ -66,7 +68,8 @@ public class OsLogoComp extends SimpleComp {
AppResources.with(AppResources.XPIPE_MODULE, "img/os", file -> {
try (var list = Files.list(file)) {
list.filter(path -> path.toString().endsWith(".png")
&& !path.toString().endsWith(LINUX_DEFAULT_24) && !path.toString().endsWith("-40.png"))
&& !path.toString().endsWith(LINUX_DEFAULT_24)
&& !path.toString().endsWith("-40.png"))
.map(path -> FileNames.getFileName(path.toString()))
.forEach(path -> {
var base = path.replace("-dark", "").replace("-24.png", ".svg");

View file

@ -199,7 +199,8 @@ public class StoreCreationComp extends DialogComp {
(e, context, validated) -> {
try {
DataStorage.get().addStoreEntryIfNotPresent(e);
if (context != null && validated
if (context != null
&& validated
&& e.getProvider().shouldShowScan()
&& AppPrefs.get()
.openConnectionSearchWindowOnConnectionCreation()

View file

@ -97,7 +97,8 @@ public class StoreCreationMenu {
var item = new MenuItem();
item.textProperty().bind(dataStoreProvider.displayName());
item.setGraphic(PrettyImageHelper.ofFixedSizeSquare(dataStoreProvider.getDisplayIconFileName(null), 16).createRegion());
item.setGraphic(PrettyImageHelper.ofFixedSizeSquare(dataStoreProvider.getDisplayIconFileName(null), 16)
.createRegion());
item.setOnAction(event -> {
StoreCreationComp.showCreation(dataStoreProvider, category);
event.consume();

View file

@ -245,15 +245,14 @@ public abstract class StoreEntryComp extends SimpleComp {
button.apply(new ContextMenuAugment<>(
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, keyEvent -> false, () -> {
var cm = ContextMenuHelper.create();
branch.getChildren(getWrapper().getEntry().ref())
.stream()
branch.getChildren(getWrapper().getEntry().ref()).stream()
.filter(actionProvider -> getWrapper().showActionProvider(actionProvider))
.forEach(childProvider -> {
var menu = buildMenuItemForAction(childProvider);
if (menu != null) {
cm.getItems().add(menu);
}
});
var menu = buildMenuItemForAction(childProvider);
if (menu != null) {
cm.getItems().add(menu);
}
});
return cm;
}));
}

View file

@ -9,8 +9,10 @@ import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.util.ThreadHelper;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import lombok.Getter;
import java.time.Duration;
@ -155,7 +157,8 @@ public class StoreEntryWrapper {
summary.setValue(null);
} else {
try {
summary.setValue(entry.getProvider() != null ? entry.getProvider().summaryString(this) : null);
summary.setValue(
entry.getProvider() != null ? entry.getProvider().summaryString(this) : null);
} catch (Exception ex) {
// Summary creation might fail or have a bug
ErrorEvent.fromThrowable(ex).handle();

View file

@ -3,12 +3,14 @@ package io.xpipe.app.comp.store;
import io.xpipe.app.fxcomps.SimpleComp;
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
import io.xpipe.app.fxcomps.impl.TooltipAugment;
import javafx.beans.binding.Bindings;
import javafx.geometry.Pos;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import lombok.AllArgsConstructor;
import org.kordamp.ikonli.javafx.FontIcon;

View file

@ -133,7 +133,8 @@ public class StoreNotesComp extends Comp<StoreNotesComp.Structure> {
popover.setTitle(wrapper.getName().getValue());
popover.showingProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
n.setValue(new StoreNotes(n.getValue().getCommited(), n.getValue().getCommited()));
n.setValue(
new StoreNotes(n.getValue().getCommited(), n.getValue().getCommited()));
DataStorage.get().saveAsync();
ref.set(null);
}

View file

@ -70,10 +70,14 @@ public class StoreSectionComp extends Comp<CompStructure<VBox>> {
private Comp<CompStructure<Button>> createExpandButton() {
var expandButton = new IconButtonComp(
Bindings.createObjectBinding(
() -> new LabelGraphic.IconGraphic(section.getWrapper().getExpanded().get()
&& section.getShownChildren().getList().size() > 0
? "mdal-keyboard_arrow_down"
: "mdal-keyboard_arrow_right"),
() -> new LabelGraphic.IconGraphic(
section.getWrapper().getExpanded().get()
&& section.getShownChildren()
.getList()
.size()
> 0
? "mdal-keyboard_arrow_down"
: "mdal-keyboard_arrow_right"),
section.getWrapper().getExpanded(),
section.getShownChildren().getList()),
() -> {

View file

@ -55,9 +55,7 @@ public class StoreSectionMiniComp extends Comp<CompStructure<VBox>> {
.apply(struc -> {
struc.get()
.setGraphic(PrettyImageHelper.ofFixedSize(
section.getWrapper().getIconFile(),
16,
16)
section.getWrapper().getIconFile(), 16, 16)
.createRegion());
})
.apply(struc -> {
@ -79,7 +77,8 @@ public class StoreSectionMiniComp extends Comp<CompStructure<VBox>> {
&& section.getShownChildren().getList().size() > 0);
var button = new IconButtonComp(
Bindings.createObjectBinding(
() -> new LabelGraphic.IconGraphic(expanded.get() ? "mdal-keyboard_arrow_down" : "mdal-keyboard_arrow_right"),
() -> new LabelGraphic.IconGraphic(
expanded.get() ? "mdal-keyboard_arrow_down" : "mdal-keyboard_arrow_right"),
expanded),
() -> {
expanded.set(!expanded.get());

View file

@ -9,6 +9,7 @@ import io.xpipe.app.fxcomps.util.LabelGraphic;
import io.xpipe.app.prefs.AppPrefsComp;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.LicenseProvider;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
@ -16,6 +17,7 @@ import javafx.beans.value.ObservableValue;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
@ -117,18 +119,18 @@ public class AppLayoutModel {
() -> Hyperlinks.open(
"http://localhost:" + AppBeaconServer.get().getPort()),
null)
// new Entry(
// AppI18n.observable("webtop"),
// "mdi2d-desktop-mac",
// null,
// () -> Hyperlinks.open(Hyperlinks.GITHUB_WEBTOP),
// null)
));
// new Entry(
// AppI18n.observable("webtop"),
// "mdi2d-desktop-mac",
// null,
// () -> Hyperlinks.open(Hyperlinks.GITHUB_WEBTOP),
// null)
));
var now = Instant.now();
var zone = ZoneId.of(ZoneId.SHORT_IDS.get("PST"));
var phStart = ZonedDateTime.of(2024,10,22,0,1, 0, 0, zone).toInstant();
var phEnd = ZonedDateTime.of(2024,10,22,23,59, 0, 0, zone).toInstant();
var phStart = ZonedDateTime.of(2024, 10, 22, 0, 1, 0, 0, zone).toInstant();
var phEnd = ZonedDateTime.of(2024, 10, 22, 23, 59, 0, 0, zone).toInstant();
var phShow = now.isAfter(phStart) && now.isBefore(phEnd);
if (phShow) {
l.add(new Entry(
@ -150,5 +152,10 @@ public class AppLayoutModel {
double browserConnectionsWidth;
}
public record Entry(ObservableValue<String> name, LabelGraphic icon, Comp<?> comp, Runnable action, KeyCombination combination) {}
public record Entry(
ObservableValue<String> name,
LabelGraphic icon,
Comp<?> comp,
Runnable action,
KeyCombination combination) {}
}

View file

@ -11,10 +11,12 @@ import io.xpipe.app.resources.AppResources;
import io.xpipe.app.util.PlatformState;
import io.xpipe.app.util.WindowsRegistry;
import io.xpipe.core.process.OsType;
import javafx.geometry.Insets;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import lombok.Getter;
import java.nio.file.Files;

View file

@ -2,6 +2,7 @@ package io.xpipe.app.core.check;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.PlatformState;
import javafx.application.ConditionalFeature;
import javafx.application.Platform;

View file

@ -11,7 +11,8 @@ public class AppJavaOptionsCheck {
}
ErrorEvent.fromMessage(
"You have configured the global environment variable _JAVA_OPTIONS=%s on your system.".formatted(env)
"You have configured the global environment variable _JAVA_OPTIONS=%s on your system."
.formatted(env)
+ " This will forcefully apply all custom JVM options to XPipe and can cause a variety of different issues."
+ " Please remove this global environment variable and use local configuration instead for your other JVM programs.")
.noDefaultActions()

View file

@ -13,6 +13,7 @@ import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.update.UpdateChangelogAlert;
import io.xpipe.app.util.NativeBridge;
import io.xpipe.app.util.ThreadHelper;
import javafx.stage.Stage;
public class GuiMode extends PlatformMode {

View file

@ -16,7 +16,9 @@ import io.xpipe.app.util.XPipeSession;
import io.xpipe.core.util.FailableRunnable;
import io.xpipe.core.util.XPipeDaemonMode;
import io.xpipe.core.util.XPipeInstallation;
import javafx.application.Platform;
import lombok.Getter;
import java.util.ArrayList;

View file

@ -10,6 +10,7 @@ import io.xpipe.app.resources.AppImages;
import io.xpipe.app.update.UpdateAvailableAlert;
import io.xpipe.app.util.PlatformState;
import io.xpipe.app.util.ThreadHelper;
import javafx.application.Application;
public abstract class PlatformMode extends OperationMode {

View file

@ -1,7 +1,5 @@
package io.xpipe.app.fxcomps.impl;
import atlantafx.base.controls.Popover;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.comp.store.*;
import io.xpipe.app.core.AppFont;
@ -15,6 +13,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.DataStoreCategoryChoiceComp;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.store.ShellStore;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
@ -26,6 +25,9 @@ import javafx.scene.control.MenuButton;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import atlantafx.base.controls.Popover;
import atlantafx.base.theme.Styles;
import lombok.RequiredArgsConstructor;
import org.kordamp.ikonli.javafx.FontIcon;

View file

@ -1,16 +1,18 @@
package io.xpipe.app.fxcomps.impl;
import atlantafx.base.theme.Styles;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.CompStructure;
import io.xpipe.app.fxcomps.SimpleCompStructure;
import io.xpipe.app.fxcomps.util.LabelGraphic;
import io.xpipe.app.fxcomps.util.PlatformThread;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.css.Size;
import javafx.css.SizeUnits;
import javafx.scene.control.Button;
import atlantafx.base.theme.Styles;
import org.kordamp.ikonli.javafx.FontIcon;
public class IconButtonComp extends Comp<CompStructure<Button>> {

View file

@ -17,6 +17,7 @@ import io.xpipe.app.storage.DataColor;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.util.ContextMenuHelper;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.css.PseudoClass;
@ -31,6 +32,7 @@ import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Region;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.kordamp.ikonli.javafx.FontIcon;

View file

@ -42,10 +42,7 @@ public class AppPrefs {
mapVaultSpecific(new SimpleBooleanProperty(false), "dontAutomaticallyStartVmSshServer", Boolean.class);
final BooleanProperty dontAcceptNewHostKeys =
mapVaultSpecific(new SimpleBooleanProperty(false), "dontAcceptNewHostKeys", Boolean.class);
public final BooleanProperty performanceMode = map(
new SimpleBooleanProperty(),
"performanceMode",
Boolean.class);
public final BooleanProperty performanceMode = map(new SimpleBooleanProperty(), "performanceMode", Boolean.class);
public final BooleanProperty useBundledTools =
map(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class);
public final ObjectProperty<AppTheme.Theme> theme =

View file

@ -3,8 +3,10 @@ package io.xpipe.app.resources;
import io.xpipe.app.core.AppExtensionManager;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import org.apache.commons.io.FilenameUtils;
import java.awt.image.BufferedImage;

View file

@ -361,7 +361,8 @@ public abstract class DataStorage {
}
@SuppressWarnings("unchecked")
public <T extends ValidationContext<?>> boolean refreshChildren(DataStoreEntry e, T context, boolean throwOnFail) throws Exception {
public <T extends ValidationContext<?>> boolean refreshChildren(DataStoreEntry e, T context, boolean throwOnFail)
throws Exception {
if (!(e.getStore() instanceof FixedHierarchyStore<?> h)) {
return false;
}
@ -377,9 +378,10 @@ public abstract class DataStorage {
}
}
newChildren = ((FixedHierarchyStore<T>)h).listChildren(context).stream()
.filter(dataStoreEntryRef -> dataStoreEntryRef != null && dataStoreEntryRef.get() != null)
.toList();
newChildren = ((FixedHierarchyStore<T>) h)
.listChildren(context).stream()
.filter(dataStoreEntryRef -> dataStoreEntryRef != null && dataStoreEntryRef.get() != null)
.toList();
} catch (Exception ex) {
if (throwOnFail) {
throw ex;

View file

@ -1,17 +1,18 @@
package io.xpipe.app.storage;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.resources.SystemIcons;
import io.xpipe.core.store.*;
import io.xpipe.core.util.JacksonMapper;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.resources.SystemIcons;
import io.xpipe.core.store.*;
import io.xpipe.core.util.JacksonMapper;
import lombok.*;
import lombok.experimental.NonFinal;
import org.apache.commons.io.FileUtils;
@ -172,15 +173,13 @@ public class DataStoreEntry extends StorageElement {
return entry;
}
public String getEffectiveIconFile() {
if (getValidity() == Validity.LOAD_FAILED) {
return "disabled_icon.png";
}
if (icon == null) {
return getProvider()
.getDisplayIconFileName(getStore());
return getProvider().getDisplayIconFileName(getStore());
}
return "app:system/" + icon + ".svg";
@ -530,7 +529,8 @@ public class DataStoreEntry extends StorageElement {
}
@SuppressWarnings("unchecked")
public <T> ValidationContext<?> validateAndKeepOpenOrThrowAndClose(ValidationContext<?> existingContext) throws Throwable {
public <T> ValidationContext<?> validateAndKeepOpenOrThrowAndClose(ValidationContext<?> existingContext)
throws Throwable {
if (store == null) {
return null;
}
@ -542,7 +542,9 @@ public class DataStoreEntry extends StorageElement {
try {
store.checkComplete();
incrementBusyCounter();
ValidationContext<T> context = existingContext != null ? (ValidationContext<T>) existingContext : (ValidationContext<T>) l.createContext();
ValidationContext<T> context = existingContext != null
? (ValidationContext<T>) existingContext
: (ValidationContext<T>) l.createContext();
if (context == null) {
return null;
}

View file

@ -130,8 +130,7 @@ public interface WezTerminalType extends ExternalTerminalType {
.readStdoutOrThrow();
var path = Path.of(pathOut);
var spawn = sc.command(CommandBuilder.of()
.addFile(path
.resolve("Contents")
.addFile(path.resolve("Contents")
.resolve("MacOS")
.resolve("wezterm")
.toString())
@ -140,8 +139,7 @@ public interface WezTerminalType extends ExternalTerminalType {
.executeAndCheck();
if (!spawn) {
ExternalApplicationHelper.startAsync(CommandBuilder.of()
.addFile(path
.resolve("Contents")
.addFile(path.resolve("Contents")
.resolve("MacOS")
.resolve("wezterm-gui")
.toString())

View file

@ -5,6 +5,7 @@ import io.xpipe.app.core.AppStyle;
import io.xpipe.app.core.AppTheme;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.impl.TextFieldComp;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;

View file

@ -11,7 +11,9 @@ import java.util.Optional;
public class CommandSupport {
public static Optional<String> findProgram(ShellControl processControl, String name) throws Exception {
var out = processControl.command(processControl.getShellDialect().getWhichCommand(name)).readStdoutIfPossible();
var out = processControl
.command(processControl.getShellDialect().getWhichCommand(name))
.readStdoutIfPossible();
return out.flatMap(s -> s.lines().findFirst()).map(String::trim);
}

View file

@ -14,8 +14,10 @@ public class Hyperlinks {
public static final String DISCORD = "https://discord.gg/8y89vS8cRb";
public static final String GITHUB_WEBTOP = "https://github.com/xpipe-io/xpipe-webtop";
public static final String SELFHST_ICONS = "https://github.com/selfhst/icons";
public static final String SLACK = "https://join.slack.com/t/XPipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg";
public static final String PRODUCT_HUNT = "https://www.producthunt.com/posts/xpipe?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-xpipe";
public static final String SLACK =
"https://join.slack.com/t/XPipe/shared_invite/zt-1awjq0t5j-5i4UjNJfNe1VN4b_auu6Cg";
public static final String PRODUCT_HUNT =
"https://www.producthunt.com/posts/xpipe?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-xpipe";
static final String[] browsers = {
"xdg-open", "google-chrome", "firefox", "opera", "konqueror", "mozilla", "gnome-open", "open"

View file

@ -74,5 +74,4 @@ public class ScanAlert {
stage -> new ScanDialog(
stage, initialStore != null ? initialStore.ref() : null, applicable, shellValidationContext));
}
}

View file

@ -14,6 +14,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.ShellStore;
import io.xpipe.core.store.ShellValidationContext;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
@ -36,14 +37,16 @@ class ScanDialog extends DialogComp {
private final BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable;
private final Stage window;
private final ObjectProperty<DataStoreEntryRef<ShellStore>> entry;
private final ListProperty<ScanProvider.ScanOperation> selected = new SimpleListProperty<>(FXCollections.observableArrayList());
private final ListProperty<ScanProvider.ScanOperation> selected =
new SimpleListProperty<>(FXCollections.observableArrayList());
private final BooleanProperty busy = new SimpleBooleanProperty();
private ShellValidationContext shellValidationContext;
ScanDialog(
Stage window, DataStoreEntryRef<ShellStore> entry, BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable,
ShellValidationContext shellValidationContext
) {
Stage window,
DataStoreEntryRef<ShellStore> entry,
BiFunction<DataStoreEntry, ShellControl, List<ScanProvider.ScanOperation>> applicable,
ShellValidationContext shellValidationContext) {
this.window = window;
this.initialStore = entry;
this.entry = new SimpleObjectProperty<>(entry);
@ -74,7 +77,9 @@ class ScanDialog extends DialogComp {
for (var a : copy) {
// If the user decided to remove the selected entry
// while the scan is running, just return instantly
if (!DataStorage.get().getStoreEntriesSet().contains(entry.get().get())) {
if (!DataStorage.get()
.getStoreEntriesSet()
.contains(entry.get().get())) {
return;
}
@ -115,10 +120,17 @@ class ScanDialog extends DialogComp {
StackPane stackPane = new StackPane();
stackPane.getStyleClass().add("scan-list");
var b = new OptionsBuilder().name("scanAlertChoiceHeader")
var b = new OptionsBuilder()
.name("scanAlertChoiceHeader")
.description("scanAlertChoiceHeaderDescription")
.addComp(new DataStoreChoiceComp<>(DataStoreChoiceComp.Mode.OTHER, null, entry, ShellStore.class, store1 -> true,
StoreViewState.get().getAllConnectionsCategory()).disable(new SimpleBooleanProperty(initialStore != null)))
.addComp(new DataStoreChoiceComp<>(
DataStoreChoiceComp.Mode.OTHER,
null,
entry,
ShellStore.class,
store1 -> true,
StoreViewState.get().getAllConnectionsCategory())
.disable(new SimpleBooleanProperty(initialStore != null)))
.name("scanAlertHeader")
.description("scanAlertHeaderDescription")
.addComp(Comp.of(() -> stackPane).vgrow())
@ -152,7 +164,8 @@ class ScanDialog extends DialogComp {
shellValidationContext = null;
}
shellValidationContext = new ShellValidationContext(newValue.getStore().control().withoutLicenseCheck().start());
shellValidationContext = new ShellValidationContext(
newValue.getStore().control().withoutLicenseCheck().start());
var a = applicable.apply(entry.get().get(), shellValidationContext.get());
Platform.runLater(() -> {
@ -161,8 +174,9 @@ class ScanDialog extends DialogComp {
return;
}
selected.setAll(
a.stream().filter(scanOperation -> scanOperation.isDefaultSelected() && !scanOperation.isDisabled()).toList());
selected.setAll(a.stream()
.filter(scanOperation -> scanOperation.isDefaultSelected() && !scanOperation.isDisabled())
.toList());
Function<ScanProvider.ScanOperation, String> nameFunc = (ScanProvider.ScanOperation s) -> {
var n = AppI18n.get(s.getNameKey());
if (s.getLicensedFeatureId() == null) {
@ -170,10 +184,14 @@ class ScanDialog extends DialogComp {
}
var suffix = LicenseProvider.get().getFeature(s.getLicensedFeatureId());
return n + suffix.getDescriptionSuffix().map(d -> " (" + d + ")").orElse("");
return n
+ suffix.getDescriptionSuffix()
.map(d -> " (" + d + ")")
.orElse("");
};
var r = new ListSelectorComp<>(a, nameFunc, selected, scanOperation -> scanOperation.isDisabled(),
a.size() > 3).createRegion();
var r = new ListSelectorComp<>(
a, nameFunc, selected, scanOperation -> scanOperation.isDisabled(), a.size() > 3)
.createRegion();
stackPane.getChildren().add(r);
});
});

View file

@ -34,11 +34,14 @@ public class SimpleScriptQuickEditAction implements ActionProvider {
@Override
public void execute() {
var predefined = DataStorage.get().getStoreCategoryIfPresent(ref.get().getCategoryUuid())
.map(category -> category.getUuid().equals(DataStorage.PREDEFINED_SCRIPTS_CATEGORY_UUID))
.orElse(false) &&
Arrays.stream(PredefinedScriptStore.values())
.anyMatch(predefinedScriptStore -> predefinedScriptStore.getName().equals(ref.get().getName()));
var predefined = DataStorage.get()
.getStoreCategoryIfPresent(ref.get().getCategoryUuid())
.map(category -> category.getUuid().equals(DataStorage.PREDEFINED_SCRIPTS_CATEGORY_UUID))
.orElse(false)
&& Arrays.stream(PredefinedScriptStore.values())
.anyMatch(predefinedScriptStore -> predefinedScriptStore
.getName()
.equals(ref.get().getName()));
if (predefined) {
StoreCreationComp.showEdit(ref.get());
return;

View file

@ -22,11 +22,13 @@ import io.xpipe.app.util.Validator;
import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.util.Identifiers;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import lombok.SneakyThrows;
import java.util.ArrayList;
@ -218,8 +220,12 @@ public class SimpleScriptStoreProvider implements EnabledParentStoreProvider, Da
var file = st.isRunnableScript() ? AppI18n.get("file") : null;
var shell = st.isRunnableScript() ? AppI18n.get("shell") : null;
var runnable = st.isRunnableScript() ? AppI18n.get("hub") : null;
var type = st.getMinimumDialect() != null ? st.getMinimumDialect().getDisplayName() + " " + AppI18n.get("script") : null;
var suffix = String.join(" / ", Stream.of(init, shell, file, runnable).filter(s -> s != null).toList());
var type = st.getMinimumDialect() != null
? st.getMinimumDialect().getDisplayName() + " " + AppI18n.get("script")
: null;
var suffix = String.join(
" / ",
Stream.of(init, shell, file, runnable).filter(s -> s != null).toList());
if (!suffix.isEmpty()) {
suffix = "(" + suffix + ")";
} else {

View file

@ -5,9 +5,9 @@ import io.xpipe.app.util.FixedHierarchyStore;
import io.xpipe.app.util.Validators;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.store.FixedChildStore;
import io.xpipe.core.store.ValidationContext;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.xpipe.core.store.ValidationContext;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;