diff --git a/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java b/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java index c9d0cabb2..99e8812d8 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/SystemStateComp.java @@ -33,26 +33,49 @@ public class SystemStateComp extends SimpleComp { PlatformThread.runLaterIfNeeded(() -> fi.setIconLiteral(i)); }); - var border = new FontIcon("mdi2c-circle-outline"); + var bg = new FontIcon("mdi2s-square-rounded"); + bg.getStyleClass().add("background-icon"); + + var border = new FontIcon("mdi2s-square-rounded-outline"); border.getStyleClass().add("outer-icon"); - border.setOpacity(0.5); + border.setOpacity(0.3); var success = Styles.toDataURI( - ".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-success-emphasis; }"); + """ + .stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-success-emphasis; } + + .stacked-ikonli-font-icon > .background-icon { -fx-icon-color: -color-success-9; } + """ + ); var failure = - Styles.toDataURI(".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-danger-emphasis; }"); + Styles.toDataURI( + """ + .stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-danger-emphasis; } + + .stacked-ikonli-font-icon > .background-icon { -fx-icon-color: -color-danger-9; } + """ + ); var other = - Styles.toDataURI(".stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-accent-emphasis; }"); + Styles.toDataURI( + """ + .stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-accent-emphasis; } + + .stacked-ikonli-font-icon > .background-icon { -fx-icon-color: -color-accent-9; } + """ + ); var pane = new StackedFontIcon(); - pane.getChildren().addAll(fi, border); + pane.getChildren().addAll(bg, fi, border); pane.setAlignment(Pos.CENTER); var dataClass1 = """ .stacked-ikonli-font-icon > .outer-icon { - -fx-icon-size: 22px; + -fx-icon-size: 26px; } + .stacked-ikonli-font-icon > .background-icon { + -fx-icon-size: 26px; + } .stacked-ikonli-font-icon > .inner-icon { -fx-icon-size: 12px; } diff --git a/app/src/main/java/io/xpipe/app/comp/base/TtyWarningComp.java b/app/src/main/java/io/xpipe/app/comp/base/TtyWarningComp.java new file mode 100644 index 000000000..34e760b4e --- /dev/null +++ b/app/src/main/java/io/xpipe/app/comp/base/TtyWarningComp.java @@ -0,0 +1,50 @@ +package io.xpipe.app.comp.base; + +import atlantafx.base.theme.Styles; +import io.xpipe.app.fxcomps.SimpleComp; +import io.xpipe.app.fxcomps.impl.TooltipAugment; +import javafx.geometry.Pos; +import javafx.scene.layout.Region; +import lombok.Getter; +import org.kordamp.ikonli.javafx.FontIcon; +import org.kordamp.ikonli.javafx.StackedFontIcon; + +@Getter +public class TtyWarningComp extends SimpleComp { + + @Override + protected Region createSimple() { + var fi = new FontIcon("mdi2l-lightning-bolt"); + fi.getStyleClass().add("inner-icon"); + + var border = new FontIcon("mdi2s-square-rounded-outline"); + border.getStyleClass().add("outer-icon"); + border.setOpacity(0.5); + + var bg = new FontIcon("mdi2s-square-rounded"); + bg.getStyleClass().add("background-icon"); + + var pane = new StackedFontIcon(); + pane.getChildren().addAll(bg, fi, border); + pane.setAlignment(Pos.CENTER); + + var style = + """ + .stacked-ikonli-font-icon > .outer-icon { -fx-icon-color: -color-danger-emphasis; } + + .stacked-ikonli-font-icon > .outer-icon { + -fx-icon-size: 26px; + } + .stacked-ikonli-font-icon > .background-icon { + -fx-icon-size: 26px; + -fx-icon-color: -color-danger-9; + } + .stacked-ikonli-font-icon > .inner-icon { + -fx-icon-size: 12px; + } + """; + pane.getStylesheets().add(Styles.toDataURI(style)); + new TooltipAugment<>("ttyWarning", null).augment(pane); + return pane; + } +} diff --git a/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java b/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java index e7c7aeabf..67d820806 100644 --- a/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java +++ b/app/src/main/java/io/xpipe/app/fxcomps/impl/TooltipAugment.java @@ -10,6 +10,7 @@ import javafx.beans.value.ObservableValue; import javafx.scene.control.Tooltip; import javafx.scene.input.KeyCombination; import javafx.stage.Window; +import javafx.util.Duration; public class TooltipAugment> implements Augment { @@ -45,6 +46,7 @@ public class TooltipAugment> implements Augment { tt.setWrapText(true); tt.setMaxWidth(400); tt.getStyleClass().add("fancy-tooltip"); + tt.setHideDelay(Duration.INDEFINITE); Tooltip.install(struc.get(), tt); } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/style.css b/app/src/main/resources/io/xpipe/app/resources/style/style.css index 7a27b0317..747928eb2 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/style.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/style.css @@ -128,3 +128,7 @@ .root:dark .loading-comp { -fx-background-color: rgba(0, 0, 0, 0.5); } + +.root:light .stacked-ikonli-font-icon > .background-icon { -fx-opacity: 0; } + +.stacked-ikonli-font-icon > .background-icon { -fx-opacity: 0.2; } diff --git a/core/src/main/java/io/xpipe/core/process/ShellControl.java b/core/src/main/java/io/xpipe/core/process/ShellControl.java index 9c29ef9e7..8c274344c 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellControl.java @@ -67,6 +67,7 @@ public interface ShellControl extends ProcessControl { var s = store.getState().toBuilder() .osType(shellControl.getOsType()) .shellDialect(shellControl.getOriginalShellDialect()) + .ttyState(shellControl.getTtyState()) .running(true) .osName(shellControl.getOsName()) .build(); diff --git a/core/src/main/java/io/xpipe/core/process/ShellStoreState.java b/core/src/main/java/io/xpipe/core/process/ShellStoreState.java index 72dcc9efe..4f2d1360f 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellStoreState.java +++ b/core/src/main/java/io/xpipe/core/process/ShellStoreState.java @@ -19,6 +19,7 @@ public class ShellStoreState extends DataStoreState implements OsNameState { OsType.Any osType; String osName; ShellDialect shellDialect; + ShellTtyState ttyState; Boolean running; public boolean isRunning() { @@ -39,6 +40,7 @@ public class ShellStoreState extends DataStoreState implements OsNameState { b.osType(useNewer(osType, shellStoreState.getOsType())) .osName(useNewer(osName, shellStoreState.getOsName())) .shellDialect(useNewer(shellDialect, shellStoreState.getShellDialect())) + .ttyState(useNewer(ttyState, shellStoreState.getTtyState())) .running(useNewer(running, shellStoreState.getRunning())); } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java new file mode 100644 index 000000000..1ee97a740 --- /dev/null +++ b/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java @@ -0,0 +1,69 @@ +package io.xpipe.ext.base.store; + +import io.xpipe.app.browser.session.BrowserSessionModel; +import io.xpipe.app.comp.base.OsLogoComp; +import io.xpipe.app.comp.base.SystemStateComp; +import io.xpipe.app.comp.base.TtyWarningComp; +import io.xpipe.app.comp.store.StoreEntryComp; +import io.xpipe.app.comp.store.StoreEntryWrapper; +import io.xpipe.app.comp.store.StoreSection; +import io.xpipe.app.ext.ActionProvider; +import io.xpipe.app.ext.DataStoreProvider; +import io.xpipe.app.ext.DataStoreUsageCategory; +import io.xpipe.app.fxcomps.Comp; +import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.storage.DataStoreEntry; +import io.xpipe.app.util.TerminalLauncher; +import io.xpipe.core.process.ShellStoreState; +import io.xpipe.core.process.ShellTtyState; +import io.xpipe.core.store.ShellStore; +import io.xpipe.ext.base.script.ScriptStore; +import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; + +public interface ShellStoreProvider extends DataStoreProvider { + + default Comp createTtyWarning(StoreEntryWrapper w) { + return new TtyWarningComp().hide(Bindings.createObjectBinding( + () -> { + ShellStoreState state = (ShellStoreState) w.getPersistentState().getValue(); + return state.getTtyState() == ShellTtyState.NONE; + }, + w.getPersistentState())); + } + + @Override + default StoreEntryComp customEntryComp(StoreSection s, boolean preferLarge) { + return StoreEntryComp.create(s, createTtyWarning(s.getWrapper()), preferLarge); + } + + @Override + default ActionProvider.Action launchAction(DataStoreEntry entry) { + return new ActionProvider.Action() { + @Override + public void execute() throws Exception { + ShellStore store = entry.getStore().asNeeded(); + TerminalLauncher.open(entry, DataStorage.get().getStoreEntryDisplayName(entry), null, ScriptStore.controlWithDefaultScripts(store.control())); + } + }; + } + + @Override + default ActionProvider.Action browserAction(BrowserSessionModel sessionModel, DataStoreEntry store, BooleanProperty busy) { + return new ActionProvider.Action() { + @Override + public void execute() throws Exception { + sessionModel.openFileSystemAsync(store.ref(), null, busy); + } + }; + } + + default Comp stateDisplay(StoreEntryWrapper w) { + return new OsLogoComp(w, SystemStateComp.State.shellState(w)); + } + + @Override + default DataStoreUsageCategory getUsageCategory() { + return DataStoreUsageCategory.SHELL; + } +} diff --git a/lang/app/strings/translations_da.properties b/lang/app/strings/translations_da.properties index 24353a796..2d762ec2b 100644 --- a/lang/app/strings/translations_da.properties +++ b/lang/app/strings/translations_da.properties @@ -502,3 +502,4 @@ workspacePathDescription=Placeringen af arbejdsområdets datakatalog workspaceCreationAlertTitle=Oprettelse af arbejdsområde developerForceSshTty=Fremtving SSH TTY developerForceSshTtyDescription=Få alle SSH-forbindelser til at tildele en pty for at teste understøttelsen af en manglende stderr og en pty. +ttyWarning=Forbindelsen har tvangstildelt en pty/tty og giver ikke en separat stderr-strøm.\n\nDet kan føre til et par problemer.\n\nHvis du kan, så prøv at få forbindelseskommandoen til ikke at tildele en pty. diff --git a/lang/app/strings/translations_de.properties b/lang/app/strings/translations_de.properties index 49561f53f..3567c2c5a 100644 --- a/lang/app/strings/translations_de.properties +++ b/lang/app/strings/translations_de.properties @@ -496,3 +496,4 @@ workspacePathDescription=Der Ort des Datenverzeichnisses des Arbeitsbereichs workspaceCreationAlertTitle=Arbeitsbereich erstellen developerForceSshTty=SSH TTY erzwingen developerForceSshTtyDescription=Lass alle SSH-Verbindungen ein pty zuweisen, um die Unterstützung für einen fehlenden stderr und ein pty zu testen. +ttyWarning=Die Verbindung hat zwangsweise ein pty/tty zugewiesen und stellt keinen separaten stderr-Stream zur Verfügung.\n\nDas kann zu einigen Problemen führen.\n\nWenn du kannst, solltest du dafür sorgen, dass der Verbindungsbefehl kein pty zuweist. diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index 591ec48bb..3b484118e 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -500,3 +500,4 @@ workspacePathDescription=The location of the workspace data directory workspaceCreationAlertTitle=Workspace creation developerForceSshTty=Force SSH TTY developerForceSshTtyDescription=Make all SSH connections allocate a pty to test the support for a missing stderr and a pty. +ttyWarning=The connection has forcefully allocated a pty/tty and does not provide a separate stderr stream.\n\nThis might lead to a few problems.\n\nIf you can, look into making the connection command not allocate a pty. diff --git a/lang/app/strings/translations_es.properties b/lang/app/strings/translations_es.properties index 8177936b8..dfbe4f77b 100644 --- a/lang/app/strings/translations_es.properties +++ b/lang/app/strings/translations_es.properties @@ -483,3 +483,4 @@ workspacePathDescription=La ubicación del directorio de datos del espacio de tr workspaceCreationAlertTitle=Creación de espacios de trabajo developerForceSshTty=Forzar SSH TTY developerForceSshTtyDescription=Haz que todas las conexiones SSH asignen una pty para probar la compatibilidad con una stderr y una pty ausentes. +ttyWarning=La conexión ha asignado forzosamente un pty/tty y no proporciona un flujo stderr separado.\n\nEsto puede provocar algunos problemas.\n\nSi puedes, intenta que el comando de conexión no asigne una pty. diff --git a/lang/app/strings/translations_fr.properties b/lang/app/strings/translations_fr.properties index 1c190e175..a66860997 100644 --- a/lang/app/strings/translations_fr.properties +++ b/lang/app/strings/translations_fr.properties @@ -483,3 +483,4 @@ workspacePathDescription=L'emplacement du répertoire de données de l'espace de workspaceCreationAlertTitle=Création d'un espace de travail developerForceSshTty=Force SSH TTY developerForceSshTtyDescription=Fais en sorte que toutes les connexions SSH allouent un pty pour tester la prise en charge d'un stderr et d'un pty manquants. +ttyWarning=La connexion a alloué de force un pty/tty et ne fournit pas de flux stderr séparé.\n\nCela peut entraîner quelques problèmes.\n\nSi tu le peux, essaie de faire en sorte que la commande de connexion n'alloue pas de pty. diff --git a/lang/app/strings/translations_it.properties b/lang/app/strings/translations_it.properties index d8141d3d1..aee2efbd2 100644 --- a/lang/app/strings/translations_it.properties +++ b/lang/app/strings/translations_it.properties @@ -483,3 +483,4 @@ workspacePathDescription=La posizione della directory dei dati dell'area di lavo workspaceCreationAlertTitle=Creazione di uno spazio di lavoro developerForceSshTty=Forza SSH TTY developerForceSshTtyDescription=Fai in modo che tutte le connessioni SSH allocino una pty per testare il supporto di una stderr e di una pty mancanti. +ttyWarning=La connessione ha allocato forzatamente una pty/tty e non fornisce un flusso stderr separato.\n\nQuesto potrebbe causare alcuni problemi.\n\nSe puoi, cerca di fare in modo che il comando di connessione non allarghi una pty. diff --git a/lang/app/strings/translations_ja.properties b/lang/app/strings/translations_ja.properties index 4f617eeca..f71ef71b9 100644 --- a/lang/app/strings/translations_ja.properties +++ b/lang/app/strings/translations_ja.properties @@ -483,3 +483,4 @@ workspacePathDescription=ワークスペースのデータディレクトリの workspaceCreationAlertTitle=ワークスペースの作成 developerForceSshTty=強制SSH TTY developerForceSshTtyDescription=すべてのSSHコネクションにptyを割り当て、stderrとptyがない場合のサポートをテストする。 +ttyWarning=接続が強制的にpty/ttyを割り当て、個別のstderrストリームを提供しない。\n\nこれはいくつかの問題を引き起こす可能性がある。\n\n可能であれば、接続コマンドで pty を割り当てないようにすることを検討してほしい。 diff --git a/lang/app/strings/translations_nl.properties b/lang/app/strings/translations_nl.properties index 682e44eb6..de00729dd 100644 --- a/lang/app/strings/translations_nl.properties +++ b/lang/app/strings/translations_nl.properties @@ -483,3 +483,4 @@ workspacePathDescription=De locatie van de gegevensmap van de werkruimte workspaceCreationAlertTitle=Werkruimte maken developerForceSshTty=SSH TTY afdwingen developerForceSshTtyDescription=Laat alle SSH-verbindingen een pty toewijzen om de ondersteuning voor een ontbrekende stderr en een pty te testen. +ttyWarning=De verbinding heeft geforceerd een pty/tty toegewezen en biedt geen aparte stderr stream.\n\nDit kan tot een paar problemen leiden.\n\nAls je kunt, kijk dan of je het connection commando geen pty kunt laten toewijzen. diff --git a/lang/app/strings/translations_pt.properties b/lang/app/strings/translations_pt.properties index 70fdcdfd2..83adc3378 100644 --- a/lang/app/strings/translations_pt.properties +++ b/lang/app/strings/translations_pt.properties @@ -483,3 +483,4 @@ workspacePathDescription=A localização do diretório de dados do espaço de tr workspaceCreationAlertTitle=Criação de espaço de trabalho developerForceSshTty=Força o SSH TTY developerForceSshTtyDescription=Faz com que todas as ligações SSH atribuam um pty para testar o suporte para um stderr e um pty em falta. +ttyWarning=A ligação atribuiu à força um pty/tty e não fornece um fluxo stderr separado.\n\nIsto pode levar a alguns problemas.\n\nSe puderes, tenta fazer com que o comando de ligação não atribua um pty. diff --git a/lang/app/strings/translations_ru.properties b/lang/app/strings/translations_ru.properties index e5ba72218..a4efffb55 100644 --- a/lang/app/strings/translations_ru.properties +++ b/lang/app/strings/translations_ru.properties @@ -483,3 +483,4 @@ workspacePathDescription=Расположение каталога данных workspaceCreationAlertTitle=Создание рабочего пространства developerForceSshTty=Принудительный SSH TTY developerForceSshTtyDescription=Заставь все SSH-соединения выделять pty, чтобы проверить поддержку отсутствующего stderr и pty. +ttyWarning=Соединение принудительно выделило pty/tty и не предоставляет отдельный поток stderr.\n\nЭто может привести к нескольким проблемам.\n\nЕсли можешь, попробуй сделать так, чтобы команда подключения не выделяла pty. diff --git a/lang/app/strings/translations_tr.properties b/lang/app/strings/translations_tr.properties index 134884ccb..4e4932b77 100644 --- a/lang/app/strings/translations_tr.properties +++ b/lang/app/strings/translations_tr.properties @@ -484,3 +484,4 @@ workspacePathDescription=Çalışma alanı veri dizininin konumu workspaceCreationAlertTitle=Çalışma alanı oluşturma developerForceSshTty=SSH TTY'yi Zorla developerForceSshTtyDescription=Eksik bir stderr ve bir pty desteğini test etmek için tüm SSH bağlantılarının bir pty ayırmasını sağlayın. +ttyWarning=Bağlantı zorla bir pty/tty ayırmış ve ayrı bir stderr akışı sağlamıyor.\n\nBu durum birkaç soruna yol açabilir.\n\nEğer yapabiliyorsanız, bağlantı komutunun bir pty tahsis etmemesini sağlayın. diff --git a/lang/app/strings/translations_zh.properties b/lang/app/strings/translations_zh.properties index e3471227e..9f3d78b31 100644 --- a/lang/app/strings/translations_zh.properties +++ b/lang/app/strings/translations_zh.properties @@ -483,3 +483,4 @@ workspacePathDescription=工作区数据目录的位置 workspaceCreationAlertTitle=创建工作区 developerForceSshTty=强制 SSH TTY developerForceSshTtyDescription=让所有 SSH 连接都分配一个 pty,以测试对缺失的 stderr 和 pty 的支持。 +ttyWarning=连接强行分配了 pty/tty,且未提供单独的 stderr 流。\n\n这可能会导致一些问题。\n\n如果可以,请考虑让连接命令不分配 pty。