Implement profiles

This commit is contained in:
crschnick 2024-08-01 22:29:13 +00:00
parent aceef43f6f
commit 4358216dc6
20 changed files with 267 additions and 24 deletions

View file

@ -197,6 +197,7 @@ The distributed XPipe application consists out of two parts:
- The closed-source extensions, mostly for professional edition features, which are not included in this repository
Additional features are available in the professional edition. For more details see https://xpipe.io/pricing.
If your enterprise puts great emphasis on having access to the full source code, there are also full source-available enterprise options available.
## More links

View file

@ -482,7 +482,7 @@ public abstract class StoreEntryComp extends SimpleComp {
sc.textProperty().bind(AppI18n.observable("base.createShortcut"));
sc.setOnAction(event -> {
ThreadHelper.runFailableAsync(() -> {
DesktopShortcuts.create(
DesktopShortcuts.createCliOpen(
url,
DataStorage.get()
.getStoreEntryDisplayName(

View file

@ -55,6 +55,12 @@ public class AppGreetings {
if (set || AppProperties.get().isDevelopmentEnvironment()) {
return;
}
if (AppProperties.get().isAutoAcceptEula()) {
AppCache.update("legalAccepted", true);
return;
}
var read = new SimpleBooleanProperty();
var accepted = new SimpleBooleanProperty();
AppWindowHelper.showBlockingAlert(alert -> {

View file

@ -42,6 +42,7 @@ public class AppProperties {
boolean locatePtb;
boolean locatorVersionCheck;
boolean isTest;
boolean autoAcceptEula;
public AppProperties() {
var appDir = Path.of(System.getProperty("user.dir")).resolve("app");
@ -107,6 +108,9 @@ public class AppProperties {
.map(s -> !Boolean.parseBoolean(s))
.orElse(true);
isTest = isJUnitTest();
autoAcceptEula = Optional.ofNullable(System.getProperty("io.xpipe.app.acceptEula"))
.map(Boolean::parseBoolean)
.orElse(false);
}
private static boolean isJUnitTest() {

View file

@ -175,6 +175,7 @@ public class AppPrefs {
new SecurityCategory(),
new HttpApiCategory(),
new WorkflowCategory(),
new ProfilesCategory(),
new TroubleshootCategory(),
new DeveloperCategory())
.filter(appPrefsCategory -> appPrefsCategory.show())

View file

@ -0,0 +1,75 @@
package io.xpipe.app.prefs;
import io.xpipe.app.core.AppFont;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.DesktopHelper;
import io.xpipe.app.util.DesktopShortcuts;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType;
import io.xpipe.core.util.XPipeInstallation;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.scene.control.ButtonType;
import org.apache.commons.io.FileUtils;
import java.nio.file.Files;
public class ProfileCreationAlert {
public static void showAsync() {
ThreadHelper.runFailableAsync(() -> {
show();
});
}
private static void show() throws Exception {
var name = new SimpleObjectProperty<>("New profile");
var path = new SimpleObjectProperty<>(AppProperties.get().getDataDir());
var show = AppWindowHelper.showBlockingAlert(alert -> {
alert.setTitle(AppI18n.get("profileCreationAlertTitle"));
var content = new OptionsBuilder()
.nameAndDescription("profileName")
.addString(name)
.nameAndDescription("profilePath")
.addPath(path)
.buildComp()
.minWidth(500)
.padding(new Insets(10))
.apply(struc -> AppFont.small(struc.get()))
.createRegion();
alert.getButtonTypes().add(ButtonType.CANCEL);
alert.getButtonTypes().add(ButtonType.OK);
alert.getDialogPane().setContent(content);
})
.map(b -> b.getButtonData().isDefaultButton())
.orElse(false);
if (!show || name.get() == null || path.get() == null) {
return;
}
if (Files.exists(path.get()) && !FileUtils.isEmptyDirectory(path.get().toFile())) {
ErrorEvent.fromMessage("New profile directory is not empty").expected().handle();
return;
}
var shortcutName = (AppProperties.get().isStaging() ? "XPipe PTB" : "XPipe") + " (" + name.get() + ")";
var file = switch (OsType.getLocal()) {
case OsType.Windows w -> {
var exec = XPipeInstallation.getCurrentInstallationBasePath().resolve(XPipeInstallation.getDaemonExecutablePath(w)).toString();
yield DesktopShortcuts.create(exec, "-Dio.xpipe.app.dataDir=\"" + path.get().toString() + "\" -Dio.xpipe.app.acceptEula=true", shortcutName);
}
default -> {
var exec = XPipeInstallation.getCurrentInstallationBasePath().resolve(XPipeInstallation.getRelativeCliExecutablePath(OsType.getLocal())).toString();
yield DesktopShortcuts.create(exec, "-d \"" + path.get().toString() + "\" --accept-eula", shortcutName);
}
};
DesktopHelper.browseFileInDirectory(file);
OperationMode.close();
}
}

View file

@ -0,0 +1,26 @@
package io.xpipe.app.prefs;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.util.OptionsBuilder;
public class ProfilesCategory extends AppPrefsCategory {
@Override
protected String getId() {
return "profiles";
}
@Override
protected Comp<?> create() {
return new OptionsBuilder()
.addTitle("manageProfiles")
.sub(new OptionsBuilder()
.nameAndDescription("profileAdd")
.addComp(
new ButtonComp(AppI18n.observable("addProfile"),
ProfileCreationAlert::showAsync)))
.buildComp();
}
}

View file

@ -4,27 +4,31 @@ import io.xpipe.core.process.OsType;
import io.xpipe.core.util.XPipeInstallation;
import java.nio.file.Files;
import java.nio.file.Path;
public class DesktopShortcuts {
private static void createWindowsShortcut(String target, String name) throws Exception {
private static Path createWindowsShortcut(String executable, String args, String name) throws Exception {
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
var shortcutTarget = XPipeInstallation.getLocalDefaultCliExecutable();
var shortcutPath = DesktopHelper.getDesktopDirectory().resolve(name + ".lnk");
var content = String.format(
"""
set "TARGET=%s"
set "SHORTCUT=%s"
set PWS=powershell.exe -ExecutionPolicy Restricted -NoLogo -NonInteractive -NoProfile
%%PWS%% -Command "$ws = New-Object -ComObject WScript.Shell; $s = $ws.CreateShortcut('%%SHORTCUT%%'); $S.IconLocation='%s'; $S.WindowStyle=7; $S.TargetPath = '%%TARGET%%'; $S.Arguments = 'open %s'; $S.Save()"
$TARGET="%s"
$SHORTCUT="%s"
$ws = New-Object -ComObject WScript.Shell
$s = $ws.CreateShortcut("$SHORTCUT")
$S.IconLocation='%s'
$S.WindowStyle=7
$S.TargetPath = "$TARGET"
$S.Arguments = '%s'
$S.Save()
""",
shortcutTarget, shortcutPath, icon, target);
LocalShell.getShell().executeSimpleCommand(content);
executable, shortcutPath, icon, args);
LocalShell.getLocalPowershell().executeSimpleCommand(content);
return shortcutPath;
}
private static void createLinuxShortcut(String target, String name) throws Exception {
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
private static Path createLinuxShortcut(String executable, String args, String name) throws Exception {
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
var content = String.format(
"""
@ -32,19 +36,19 @@ public class DesktopShortcuts {
Type=Application
Name=%s
Comment=Open with XPipe
Exec="%s" open %s
Exec="%s" %s
Icon=%s
Terminal=false
Categories=Utility;Development;
""",
name, exec, target, icon);
name, executable, args, icon);
var file = DesktopHelper.getDesktopDirectory().resolve(name + ".desktop");
Files.writeString(file, content);
file.toFile().setExecutable(true);
return file;
}
private static void createMacOSShortcut(String target, String name) throws Exception {
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
private static Path createMacOSShortcut(String executable, String args, String name) throws Exception {
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
var base = DesktopHelper.getDesktopDirectory().resolve(name + ".app");
var content = String.format(
@ -52,18 +56,18 @@ public class DesktopShortcuts {
#!/usr/bin/env sh
"%s" open %s
""",
exec, target);
executable, args);
try (var pc = LocalShell.getShell()) {
pc.getShellDialect().deleteFileOrDirectory(pc, base.toString()).executeAndCheck();
pc.executeSimpleCommand(pc.getShellDialect().getMkdirsCommand(base + "/Contents/MacOS"));
pc.executeSimpleCommand(pc.getShellDialect().getMkdirsCommand(base + "/Contents/Resources"));
var executable = base + "/Contents/MacOS/" + name;
var macExec = base + "/Contents/MacOS/" + name;
pc.getShellDialect()
.createScriptTextFileWriteCommand(pc, content, executable)
.createScriptTextFileWriteCommand(pc, content, macExec)
.execute();
pc.executeSimpleCommand("chmod ugo+x \"" + executable + "\"");
pc.executeSimpleCommand("chmod ugo+x \"" + macExec + "\"");
pc.getShellDialect()
.createTextFileWriteCommand(pc, "APPL????", base + "/Contents/PkgInfo")
@ -85,15 +89,21 @@ public class DesktopShortcuts {
.execute();
pc.executeSimpleCommand("cp \"" + icon + "\" \"" + base + "/Contents/Resources/icon.icns\"");
}
return base;
}
public static void create(String target, String name) throws Exception {
public static Path createCliOpen(String action, String name) throws Exception {
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
return create(exec, "open " + action, name);
}
public static Path create(String executable, String args, String name) throws Exception {
if (OsType.getLocal().equals(OsType.WINDOWS)) {
createWindowsShortcut(target, name);
return createWindowsShortcut(executable, args, name);
} else if (OsType.getLocal().equals(OsType.LINUX)) {
createLinuxShortcut(target, name);
return createLinuxShortcut(executable, args, name);
} else {
createMacOSShortcut(target, name);
return createMacOSShortcut(executable, args, name);
}
}
}

View file

@ -490,3 +490,13 @@ closeLeftTabs=Luk faner til venstre
closeRightTabs=Luk faner til højre
addSerial=Seriel ...
connect=Forbind
profiles=Profiler
manageProfiles=Administrer profiler
addProfile=Tilføj profil ...
profileAdd=Tilføj en ny profil
profileAddDescription=Profiler er forskellige konfigurationer til at køre XPipe. Hver profil har et datakatalog, hvor alle data gemmes lokalt. Det omfatter forbindelsesdata, indstillinger og meget mere.\n\nHvis du bruger synkroniseringsfunktionen, kan du også vælge at synkronisere hver profil med et forskelligt git-repository.
profileName=Navn på profil
profileNameDescription=Profilens visningsnavn
profilePath=Profil sti
profilePathDescription=Placeringen af profilens datakatalog
profileCreationAlertTitle=Oprettelse af profil

View file

@ -484,3 +484,13 @@ closeLeftTabs=Tabs nach links schließen
closeRightTabs=Tabs nach rechts schließen
addSerial=Serielle ...
connect=Verbinden
profiles=Profile
manageProfiles=Profile verwalten
addProfile=Profil hinzufügen ...
profileAdd=Ein neues Profil hinzufügen
profileAddDescription=Profile sind unterschiedliche Konfigurationen für den Betrieb von XPipe. Jedes Profil hat ein Datenverzeichnis, in dem alle Daten lokal gespeichert werden. Dazu gehören Verbindungsdaten, Einstellungen und mehr.\n\nWenn du die Synchronisierungsfunktion nutzt, kannst du jedes Profil auch mit einem anderen Git-Repository synchronisieren.
profileName=Profilname
profileNameDescription=Der Anzeigename des Profils
profilePath=Profilpfad
profilePathDescription=Der Ort des Profildatenverzeichnisses
profileCreationAlertTitle=Profil erstellen

View file

@ -488,3 +488,13 @@ closeLeftTabs=Close tabs to the left
closeRightTabs=Close tabs to the right
addSerial=Serial ...
connect=Connect
profiles=Profiles
manageProfiles=Manage profiles
addProfile=Add profile ...
profileAdd=Add a new profile
profileAddDescription=Profiles are distinct configurations for running XPipe. Every profile has a data directory where all data is stored locally. This includes connection data, settings, and more.\n\nIf you use the synchronization feature, you can also choose to synchronize each profile with a different git repository.
profileName=Profile name
profileNameDescription=The display name of the profile
profilePath=Profile path
profilePathDescription=The location of the profile data directory
profileCreationAlertTitle=Profile creation

View file

@ -471,3 +471,13 @@ closeLeftTabs=Cerrar pestañas a la izquierda
closeRightTabs=Cerrar pestañas a la derecha
addSerial=Serie ...
connect=Conecta
profiles=Perfiles
manageProfiles=Gestionar perfiles
addProfile=Añadir perfil ...
profileAdd=Añadir un nuevo perfil
profileAddDescription=Los perfiles son configuraciones distintas para ejecutar XPipe. Cada perfil tiene un directorio de datos donde se almacenan localmente todos los datos. Esto incluye datos de conexión, configuraciones y más.\n\nSi utilizas la función de sincronización, también puedes elegir sincronizar cada perfil con un repositorio git diferente.
profileName=Nombre del perfil
profileNameDescription=El nombre para mostrar del perfil
profilePath=Ruta del perfil
profilePathDescription=La ubicación del directorio de datos del perfil
profileCreationAlertTitle=Creación de perfiles

View file

@ -471,3 +471,13 @@ closeLeftTabs=Ferme les onglets à gauche
closeRightTabs=Ferme les onglets à droite
addSerial=Série ...
connect=Connecter
profiles=Profils
manageProfiles=Gérer les profils
addProfile=Ajouter un profil ...
profileAdd=Ajouter un nouveau profil
profileAddDescription=Les profils sont des configurations distinctes pour l'exécution de XPipe. Chaque profil possède un répertoire de données où toutes les données sont stockées localement. Cela comprend les données de connexion, les paramètres, et plus encore.\n\nSi tu utilises la fonction de synchronisation, tu peux aussi choisir de synchroniser chaque profil avec un dépôt git différent.
profileName=Nom du profil
profileNameDescription=Le nom d'affichage du profil
profilePath=Chemin du profil
profilePathDescription=L'emplacement du répertoire des données de profil
profileCreationAlertTitle=Création de profil

View file

@ -471,3 +471,13 @@ closeLeftTabs=Chiudere le schede a sinistra
closeRightTabs=Chiudere le schede a destra
addSerial=Seriale ...
connect=Collegare
profiles=Profili
manageProfiles=Gestire i profili
addProfile=Aggiungi profilo ...
profileAdd=Aggiungere un nuovo profilo
profileAddDescription=I profili sono configurazioni distinte per l'esecuzione di XPipe. Ogni profilo ha una directory di dati in cui vengono memorizzati tutti i dati a livello locale. Questi includono i dati di connessione, le impostazioni e altro ancora.\n\nSe utilizzi la funzione di sincronizzazione, puoi anche scegliere di sincronizzare ogni profilo con un repository git diverso.
profileName=Nome del profilo
profileNameDescription=Il nome visualizzato del profilo
profilePath=Percorso del profilo
profilePathDescription=La posizione della directory dei dati del profilo
profileCreationAlertTitle=Creazione di un profilo

View file

@ -471,3 +471,13 @@ closeLeftTabs=タブを左に閉じる
closeRightTabs=タブを右に閉じる
addSerial=シリアル ...
connect=接続する
profiles=プロフィール
manageProfiles=プロファイルを管理する
addProfile=プロフィールを追加する
profileAdd=新しいプロファイルを追加する
profileAddDescription=プロファイルは、XPipeを実行するための個別の設定である。各プロファイルには、すべてのデータがローカルに保存されるデータディレクトリがある。これには、接続データや設定などが含まれる。\n\n同期機能を使えば、各プロファイルを異なるgitリポジトリと同期させることもできる。
profileName=プロファイル名
profileNameDescription=プロファイルの表示名
profilePath=プロファイルパス
profilePathDescription=プロファイルデータのディレクトリの場所
profileCreationAlertTitle=プロファイルの作成

View file

@ -471,3 +471,13 @@ closeLeftTabs=Tabbladen naar links sluiten
closeRightTabs=Tabbladen naar rechts sluiten
addSerial=Serieel ...
connect=Maak verbinding met
profiles=Profielen
manageProfiles=Profielen beheren
addProfile=Profiel toevoegen ...
profileAdd=Een nieuw profiel toevoegen
profileAddDescription=Profielen zijn verschillende configuraties voor het uitvoeren van XPipe. Elk profiel heeft een datamap waar alle gegevens lokaal worden opgeslagen. Dit omvat verbindingsgegevens, instellingen en meer.\n\nAls je de synchronisatiefunctie gebruikt, kun je er ook voor kiezen om elk profiel met een andere git repository te synchroniseren.
profileName=Naam profiel
profileNameDescription=De weergavenaam van het profiel
profilePath=Profiel pad
profilePathDescription=De locatie van de profielgegevensmap
profileCreationAlertTitle=Profiel maken

View file

@ -471,3 +471,13 @@ closeLeftTabs=Fecha os separadores à esquerda
closeRightTabs=Fecha os separadores à direita
addSerial=Série ...
connect=Liga-te
profiles=Perfis
manageProfiles=Gerir perfis
addProfile=Adicionar perfil ...
profileAdd=Adiciona um novo perfil
profileAddDescription=Os perfis são configurações distintas para executar o XPipe. Cada perfil tem um diretório de dados onde todos os dados são armazenados localmente. Isto inclui dados de ligação, definições e muito mais.\n\nSe utilizares a funcionalidade de sincronização, também podes optar por sincronizar cada perfil com um repositório git diferente.
profileName=Nome do perfil
profileNameDescription=O nome de apresentação do perfil
profilePath=Caminho do perfil
profilePathDescription=A localização do diretório de dados do perfil
profileCreationAlertTitle=Criação de perfil

View file

@ -471,3 +471,13 @@ closeLeftTabs=Закрыть вкладки слева
closeRightTabs=Закрывать вкладки справа
addSerial=Серийный ...
connect=Connect
profiles=Профили
manageProfiles=Управляй профилями
addProfile=Добавь профиль ...
profileAdd=Добавьте новый профиль
profileAddDescription=Профили - это отдельные конфигурации для запуска XPipe. У каждого профиля есть каталог данных, где все данные хранятся локально. Сюда входят данные о подключении, настройки и многое другое.\n\nЕсли ты используешь функцию синхронизации, ты также можешь выбрать синхронизацию каждого профиля с отдельным git-репозиторием.
profileName=Имя профиля
profileNameDescription=Отображаемое имя профиля
profilePath=Путь к профилю
profilePathDescription=Расположение каталога данных профиля
profileCreationAlertTitle=Создание профиля

View file

@ -472,3 +472,13 @@ closeLeftTabs=Sekmeleri sola doğru kapatın
closeRightTabs=Sekmeleri sağa doğru kapatın
addSerial=Seri ...
connect=Bağlan
profiles=Profiller
manageProfiles=Profilleri yönetin
addProfile=Profil ekle ...
profileAdd=Yeni bir profil ekleyin
profileAddDescription=Profiller XPipe'ı çalıştırmak için farklı konfigürasyonlardır. Her profil, tüm verilerin yerel olarak depolandığı bir veri dizinine sahiptir. Buna bağlantı verileri, ayarlar ve daha fazlası dahildir.\n\nSenkronizasyon özelliğini kullanırsanız, her profili farklı bir git deposu ile senkronize etmeyi de seçebilirsiniz.
profileName=Profil adı
profileNameDescription=Profilin görünen adı
profilePath=Profil yolu
profilePathDescription=Profil veri dizininin konumu
profileCreationAlertTitle=Profil oluşturma

View file

@ -471,3 +471,13 @@ closeLeftTabs=向左关闭标签
closeRightTabs=向右关闭标签页
addSerial=串行 ...
connect=连接
profiles=简介
manageProfiles=管理配置文件
addProfile=添加配置文件...
profileAdd=添加新的简介
profileAddDescription=配置文件是运行 XPipe 的不同配置。每个配置文件都有一个数据目录,本地存储所有数据。其中包括连接数据、设置等。\n\n如果使用同步功能您还可以选择将每个配置文件与不同的 git 仓库同步。
profileName=简介名称
profileNameDescription=配置文件的显示名称
profilePath=配置文件路径
profilePathDescription=配置文件数据目录的位置
profileCreationAlertTitle=创建简介