diff --git a/backend/i18n/frontend_en.json b/backend/i18n/frontend_en.json index bdeba4151..1eea7677e 100644 --- a/backend/i18n/frontend_en.json +++ b/backend/i18n/frontend_en.json @@ -166,6 +166,7 @@ "backups.started": "Backup started, it can take several minutes to complete.", "backups.startedLabel": "Started", "backups.startFailed": "Failed to start backup.", + "chat.answer": "Here is my answer:", "chat.answers": "Answers", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.ask": "Ask", @@ -194,16 +195,6 @@ "clients.connectWizard.cliStep3": "Add your app name the CLI config", "clients.connectWizard.cliStep3Hint": "You can manage configuration to multiple apps in the CLI and switch to an app.", "clients.connectWizard.cliStep4": "Switch to your app in the CLI", - "clients.connectWizard.dotnetSdk": "Use the .NET SDK", - "clients.connectWizard.dotnetSdkDocumentation": "Documentations for the .NET SDK is available: ", - "clients.connectWizard.dotnetSdkHint": "Install the .NET SDK and establish a connection to this app.", - "clients.connectWizard.dotnetSdkStep1": "Install the .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "The SDK is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Version 14 and before: Create a client manager", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 and later: Create a client", - "clients.connectWizard.dotnetSdkStep3": "Optionally: Install the Service Extensions for the SDK", - "clients.connectWizard.dotnetSdkStep3Download": "The SDK Extension is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Optionally: Register the client manager and all clients", "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK", "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.", @@ -217,8 +208,10 @@ "clients.connectWizard.manuallyStep3": "Add the token as HTTP header to all requests", "clients.connectWizard.manuallyTokenHint": "Tokens usally expire after 30days, but you can request multiple tokens.", "clients.connectWizard.postManDocs": "Start with the Postman tutorial in the [Documentation](https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman).", + "clients.connectWizard.sdk": "Use the official SDK", "clients.connectWizard.sdkHelp": "You need another SDK?", "clients.connectWizard.sdkHelpLink": "Contact us in the Support Forum", + "clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.", "clients.connectWizard.step0Title": "Setup client", "clients.connectWizard.step1Title": "Choose connection method", "clients.connectWizard.step2Title": "Connect", @@ -387,6 +380,7 @@ "common.remember": "Don't ask again", "common.rename": "Rename", "common.renameTag": "Rename Tag", + "common.repository": "Repository", "common.requiredHint": "required", "common.reset": "Reset", "common.restore": "Restore", diff --git a/backend/i18n/frontend_fr.json b/backend/i18n/frontend_fr.json index 79632c663..94066370e 100644 --- a/backend/i18n/frontend_fr.json +++ b/backend/i18n/frontend_fr.json @@ -166,6 +166,7 @@ "backups.started": "La sauvegarde a commencé, cela peut prendre plusieurs minutes.", "backups.startedLabel": "Commencé", "backups.startFailed": "Échec du démarrage de la sauvegarde.", + "chat.answer": "Here is my answer:", "chat.answers": "Answers", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.ask": "Ask", @@ -194,22 +195,12 @@ "clients.connectWizard.cliStep3": "Ajoutez le nom de votre application à la configuration CLI", "clients.connectWizard.cliStep3Hint": "Vous pouvez gérer la configuration de plusieurs applications dans l'interface de ligne de commande et basculer vers une application.", "clients.connectWizard.cliStep4": "Basculez vers votre application dans la CLI", - "clients.connectWizard.dotnetSdk": "Utiliser le SDK .NET", - "clients.connectWizard.dotnetSdkDocumentation": "Les documentations pour le SDK .NET sont disponibles\u00A0:", - "clients.connectWizard.dotnetSdkHint": "Installez le SDK .NET et établissez une connexion à cette application.", - "clients.connectWizard.dotnetSdkStep1": "Installer le SDK .NET", - "clients.connectWizard.dotnetSdkStep1Download": "Le SDK est disponible sur [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Version 14 et antérieure : Créer un gestionnaire de clientèle", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 et supérieures : Créer un client", - "clients.connectWizard.dotnetSdkStep3": "Facultatif\u00A0: installez les extensions de service pour le SDK", - "clients.connectWizard.dotnetSdkStep3Download": "L'extension SDK est disponible sur [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Facultativement\u00A0: Enregistrez le gestionnaire de clientèle et tous les clients", - "clients.connectWizard.javascriptSdk": "Utiliser le SDK JavaScript", - "clients.connectWizard.javascriptSdkDocumentation": "Les documentations pour le SDK JavaScript sont disponibles\u00A0:", - "clients.connectWizard.javascriptSdkHint": "Installez le SDK et établissez une connexion à cette application.", - "clients.connectWizard.javascriptSdkStep1": "Installer le SDK Javascript", - "clients.connectWizard.javascriptSdkStep1Download": "Le SDK est disponible sur [npm](https://www.npmjs.com/package/@squidex/squidex", - "clients.connectWizard.javascriptSdkStep2": "Créer un client", + "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK", + "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", + "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.", + "clients.connectWizard.javascriptSdkStep1": "Install the Javascript SDK", + "clients.connectWizard.javascriptSdkStep1Download": "The SDK is available on [npm](https://www.npmjs.com/package/@squidex/squidex)", + "clients.connectWizard.javascriptSdkStep2": "Create a client", "clients.connectWizard.manually": "Connectez-vous manuellement", "clients.connectWizard.manuallyHint": "Obtenez des instructions pour établir une connexion avec Postman ou curl.", "clients.connectWizard.manuallyStep1": "Obtenir un jeton en utilisant curl", @@ -217,8 +208,10 @@ "clients.connectWizard.manuallyStep3": "Ajouter le jeton en tant qu'en-tête HTTP à toutes les requêtes", "clients.connectWizard.manuallyTokenHint": "Les jetons expirent généralement après 30 jours, mais vous pouvez demander plusieurs jetons.", "clients.connectWizard.postManDocs": "Commencez par le tutoriel Postman dans la [Documentation](https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman).", + "clients.connectWizard.sdk": "Use the official SDK", "clients.connectWizard.sdkHelp": "Vous avez besoin d'un autre SDK\u00A0?", "clients.connectWizard.sdkHelpLink": "Contactez-nous sur le forum d'assistance", + "clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.", "clients.connectWizard.step0Title": "Configurer le client", "clients.connectWizard.step1Title": "Choisissez la méthode de connexion", "clients.connectWizard.step2Title": "Connecter", @@ -387,6 +380,7 @@ "common.remember": "Ne demande plus", "common.rename": "Renommer", "common.renameTag": "Renommer la balise", + "common.repository": "Repository", "common.requiredHint": "requis", "common.reset": "Réinitialiser", "common.restore": "Restaurer", diff --git a/backend/i18n/frontend_it.json b/backend/i18n/frontend_it.json index 13043c818..fc054cebb 100644 --- a/backend/i18n/frontend_it.json +++ b/backend/i18n/frontend_it.json @@ -166,6 +166,7 @@ "backups.started": "Backup avviato, il suo completamento potrebbe richiedere alcuni minuti.", "backups.startedLabel": "Avviato", "backups.startFailed": "Non è stato possibile avviare il backup.", + "chat.answer": "Here is my answer:", "chat.answers": "Answers", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.ask": "Ask", @@ -194,16 +195,6 @@ "clients.connectWizard.cliStep3": "Inserisci il nome della tua app per la configurazione della CLI", "clients.connectWizard.cliStep3Hint": "È possibile gestire le configurazione per le diverse appi all'interno della CLI e passare ad un'app.", "clients.connectWizard.cliStep4": "Passa alla tua app usando CLI", - "clients.connectWizard.dotnetSdk": "Connetti la tua APP utilizzando SDK", - "clients.connectWizard.dotnetSdkDocumentation": "Documentations for the .NET SDK is available: ", - "clients.connectWizard.dotnetSdkHint": "Scarica l'SDK e connetti quest'app.", - "clients.connectWizard.dotnetSdkStep1": "Installa .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "L'SDK è disponibile su [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Crea un client manager", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 and later: Create a client", - "clients.connectWizard.dotnetSdkStep3": "Optionally: Install the Service Extensions for the SDK", - "clients.connectWizard.dotnetSdkStep3Download": "The SDK Extension is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Optionally: Register the client manager and all clients", "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK", "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.", @@ -217,8 +208,10 @@ "clients.connectWizard.manuallyStep3": "Aggiungi il token come header HTTP header a tutte le richieste", "clients.connectWizard.manuallyTokenHint": "Solitamente i Token scadono dopo 30 giorni, ma puoi richiedere token multipli.", "clients.connectWizard.postManDocs": "Per il tutorial Postman inizia da questo link [Documentazione](https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman).", + "clients.connectWizard.sdk": "Use the official SDK", "clients.connectWizard.sdkHelp": "Hai bisogno di un altro SDK?", "clients.connectWizard.sdkHelpLink": "Contattaci nel Forum di assistenza", + "clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.", "clients.connectWizard.step0Title": "Setup client", "clients.connectWizard.step1Title": "Scegli la tipologia di connessione", "clients.connectWizard.step2Title": "Collega", @@ -387,6 +380,7 @@ "common.remember": "Ricorda la mia decisione", "common.rename": "Rinomina", "common.renameTag": "Rename Tag", + "common.repository": "Repository", "common.requiredHint": "obbligatorio", "common.reset": "Reimposta", "common.restore": "Ripristina", diff --git a/backend/i18n/frontend_nl.json b/backend/i18n/frontend_nl.json index 42ecb41ce..14a8d8749 100644 --- a/backend/i18n/frontend_nl.json +++ b/backend/i18n/frontend_nl.json @@ -166,6 +166,7 @@ "backups.started": "Back-up gestart, het kan enkele minuten duren om te voltooien.", "backups.startedLabel": "Gestart", "backups.startFailed": "Starten van back-up is mislukt.", + "chat.answer": "Here is my answer:", "chat.answers": "Answers", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.ask": "Ask", @@ -194,16 +195,6 @@ "clients.connectWizard.cliStep3": "Voeg uw app-naam toe aan de CLI-configuratie", "clients.connectWizard.cliStep3Hint": "Je kunt de configuratie voor meerdere apps in de CLI beheren en overschakelen naar een app.", "clients.connectWizard.cliStep4": "Schakel over naar uw app in de CLI", - "clients.connectWizard.dotnetSdk": "Maak verbinding met uw app met SDK", - "clients.connectWizard.dotnetSdkDocumentation": "Documentations for the .NET SDK is available: ", - "clients.connectWizard.dotnetSdkHint": "Download een SDK en maak verbinding met deze app.", - "clients.connectWizard.dotnetSdkStep1": "Installeer de .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "De SDK is beschikbaar op [nuget] (https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Maak een klantenbeheerder", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 and later: Create a client", - "clients.connectWizard.dotnetSdkStep3": "Optionally: Install the Service Extensions for the SDK", - "clients.connectWizard.dotnetSdkStep3Download": "The SDK Extension is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Optionally: Register the client manager and all clients", "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK", "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.", @@ -217,8 +208,10 @@ "clients.connectWizard.manuallyStep3": "Voeg het token toe als HTTP-header aan alle verzoeken", "clients.connectWizard.manuallyTokenHint": "Tokens vervallen gewoonlijk na 30 dagen, maar je kunt meerdere tokens aanvragen.", "clients.connectWizard.postManDocs": "Begin met de Postman-tutorial in de [Documentatie] (https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman).", + "clients.connectWizard.sdk": "Use the official SDK", "clients.connectWizard.sdkHelp": "Heb je een andere SDK nodig?", "clients.connectWizard.sdkHelpLink": "Neem contact met ons op in het ondersteuningsforum", + "clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.", "clients.connectWizard.step0Title": "Client instellen", "clients.connectWizard.step1Title": "Kies verbindingsmethode", "clients.connectWizard.step2Title": "Verbinden", @@ -387,6 +380,7 @@ "common.remember": "Onthoud mijn keuze", "common.rename": "Hernoemen", "common.renameTag": "Hernoem Tag", + "common.repository": "Repository", "common.requiredHint": "verplicht", "common.reset": "Reset", "common.restore": "Herstellen", diff --git a/backend/i18n/frontend_pt.json b/backend/i18n/frontend_pt.json index 0872dfdef..288d6efb1 100644 --- a/backend/i18n/frontend_pt.json +++ b/backend/i18n/frontend_pt.json @@ -166,6 +166,7 @@ "backups.started": "O reforço começou, pode levar vários minutos para ser concluído.", "backups.startedLabel": "Começou", "backups.startFailed": "Falhou em começar o backup.", + "chat.answer": "Here is my answer:", "chat.answers": "Answers", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.ask": "Ask", @@ -194,16 +195,6 @@ "clients.connectWizard.cliStep3": "Adicione o nome da sua aplicação ao CLI config", "clients.connectWizard.cliStep3Hint": "Pode gerir a configuração de várias aplicações no CLI e mudar para uma aplicação.", "clients.connectWizard.cliStep4": "Mude para a sua aplicação no CLI", - "clients.connectWizard.dotnetSdk": "Conecte-se à sua App com a SDK", - "clients.connectWizard.dotnetSdkDocumentation": "Documentations for the .NET SDK is available: ", - "clients.connectWizard.dotnetSdkHint": "Descarregue um SDK e estabeleça uma ligação a esta aplicação.", - "clients.connectWizard.dotnetSdkStep1": "Instale o .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "O SDK está disponível em [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Criar um gestor de clientes", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 and later: Create a client", - "clients.connectWizard.dotnetSdkStep3": "Optionally: Install the Service Extensions for the SDK", - "clients.connectWizard.dotnetSdkStep3Download": "The SDK Extension is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Optionally: Register the client manager and all clients", "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK", "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.", @@ -217,8 +208,10 @@ "clients.connectWizard.manuallyStep3": "Adicione o token como cabeçalho HTTP a todos os pedidos", "clients.connectWizard.manuallyTokenHint": "Tokens normalmente expiram após 30 dias, mas você pode solicitar várias tokens.", "clients.connectWizard.postManDocs": "Comece com o tutorial do Carteiro na [Documentação](https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman).", + "clients.connectWizard.sdk": "Use the official SDK", "clients.connectWizard.sdkHelp": "Precisa de outro SDK?", "clients.connectWizard.sdkHelpLink": "Contacte-nos no Fórum de Apoio", + "clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.", "clients.connectWizard.step0Title": "Cliente de configuração", "clients.connectWizard.step1Title": "Escolha o método de ligação", "clients.connectWizard.step2Title": "Ligar", @@ -387,6 +380,7 @@ "common.remember": "Não pergunte de novo.", "common.rename": "Renomear", "common.renameTag": "Renomear Etiqueta", + "common.repository": "Repository", "common.requiredHint": "Necessário", "common.reset": "Reset", "common.restore": "Restaurar", diff --git a/backend/i18n/frontend_zh.json b/backend/i18n/frontend_zh.json index 28cea090c..1949dfa56 100644 --- a/backend/i18n/frontend_zh.json +++ b/backend/i18n/frontend_zh.json @@ -166,6 +166,7 @@ "backups.started": "备份已开始,可能需要几分钟才能完成。", "backups.startedLabel": "开始", "backups.startFailed": "启动备份失败。", + "chat.answer": "Here is my answer:", "chat.answers": "Answers", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.ask": "Ask", @@ -194,16 +195,6 @@ "clients.connectWizard.cliStep3": "在 CLI 配置中添加你的应用名称", "clients.connectWizard.cliStep3Hint": "您可以在 CLI 中管理多个应用程序的配置并切换到一个应用程序。", "clients.connectWizard.cliStep4": "在 CLI 中切换到您的应用程序", - "clients.connectWizard.dotnetSdk": "使用 SDK 连接到您的应用程序", - "clients.connectWizard.dotnetSdkDocumentation": "Documentations for the .NET SDK is available: ", - "clients.connectWizard.dotnetSdkHint": "下载 SDK 并建立与此应用程序的连接。", - "clients.connectWizard.dotnetSdkStep1": "安装.NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "SDK 可在 [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "创建客户端管理器", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 and later: Create a client", - "clients.connectWizard.dotnetSdkStep3": "Optionally: Install the Service Extensions for the SDK", - "clients.connectWizard.dotnetSdkStep3Download": "The SDK Extension is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Optionally: Register the client manager and all clients", "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK", "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.", @@ -217,8 +208,10 @@ "clients.connectWizard.manuallyStep3": "将令牌作为 HTTP 标头添加到所有请求中", "clients.connectWizard.manuallyTokenHint": "令牌通常会在 30 天后过期,但您可以请求多个令牌。", "clients.connectWizard.postManDocs": "从 [文档](https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman) 中的 Postman 教程开始。", + "clients.connectWizard.sdk": "Use the official SDK", "clients.connectWizard.sdkHelp": "你需要另一个 SDK?", "clients.connectWizard.sdkHelpLink": "在支持论坛联系我们", + "clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.", "clients.connectWizard.step0Title": "设置客户端", "clients.connectWizard.step1Title": "选择连接方式", "clients.connectWizard.step2Title": "连接", @@ -387,6 +380,7 @@ "common.remember": "不要再问了", "common.rename": "重命名", "common.renameTag": "Rename Tag", + "common.repository": "Repository", "common.requiredHint": "必需的", "common.reset": "重置", "common.restore": "恢复", diff --git a/backend/i18n/source/frontend_en.json b/backend/i18n/source/frontend_en.json index bdeba4151..1eea7677e 100644 --- a/backend/i18n/source/frontend_en.json +++ b/backend/i18n/source/frontend_en.json @@ -166,6 +166,7 @@ "backups.started": "Backup started, it can take several minutes to complete.", "backups.startedLabel": "Started", "backups.startFailed": "Failed to start backup.", + "chat.answer": "Here is my answer:", "chat.answers": "Answers", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.ask": "Ask", @@ -194,16 +195,6 @@ "clients.connectWizard.cliStep3": "Add your app name the CLI config", "clients.connectWizard.cliStep3Hint": "You can manage configuration to multiple apps in the CLI and switch to an app.", "clients.connectWizard.cliStep4": "Switch to your app in the CLI", - "clients.connectWizard.dotnetSdk": "Use the .NET SDK", - "clients.connectWizard.dotnetSdkDocumentation": "Documentations for the .NET SDK is available: ", - "clients.connectWizard.dotnetSdkHint": "Install the .NET SDK and establish a connection to this app.", - "clients.connectWizard.dotnetSdkStep1": "Install the .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "The SDK is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Version 14 and before: Create a client manager", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 and later: Create a client", - "clients.connectWizard.dotnetSdkStep3": "Optionally: Install the Service Extensions for the SDK", - "clients.connectWizard.dotnetSdkStep3Download": "The SDK Extension is available on [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Optionally: Register the client manager and all clients", "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK", "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.", @@ -217,8 +208,10 @@ "clients.connectWizard.manuallyStep3": "Add the token as HTTP header to all requests", "clients.connectWizard.manuallyTokenHint": "Tokens usally expire after 30days, but you can request multiple tokens.", "clients.connectWizard.postManDocs": "Start with the Postman tutorial in the [Documentation](https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman).", + "clients.connectWizard.sdk": "Use the official SDK", "clients.connectWizard.sdkHelp": "You need another SDK?", "clients.connectWizard.sdkHelpLink": "Contact us in the Support Forum", + "clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.", "clients.connectWizard.step0Title": "Setup client", "clients.connectWizard.step1Title": "Choose connection method", "clients.connectWizard.step2Title": "Connect", @@ -387,6 +380,7 @@ "common.remember": "Don't ask again", "common.rename": "Rename", "common.renameTag": "Rename Tag", + "common.repository": "Repository", "common.requiredHint": "required", "common.reset": "Reset", "common.restore": "Restore", diff --git a/backend/i18n/source/frontend_fr.json b/backend/i18n/source/frontend_fr.json index 5d610ab48..9807fbd5b 100644 --- a/backend/i18n/source/frontend_fr.json +++ b/backend/i18n/source/frontend_fr.json @@ -183,22 +183,6 @@ "clients.connectWizard.cliStep3": "Ajoutez le nom de votre application à la configuration CLI", "clients.connectWizard.cliStep3Hint": "Vous pouvez gérer la configuration de plusieurs applications dans l'interface de ligne de commande et basculer vers une application.", "clients.connectWizard.cliStep4": "Basculez vers votre application dans la CLI", - "clients.connectWizard.dotnetSdk": "Utiliser le SDK .NET", - "clients.connectWizard.dotnetSdkDocumentation": "Les documentations pour le SDK .NET sont disponibles\u00A0:", - "clients.connectWizard.dotnetSdkHint": "Installez le SDK .NET et établissez une connexion à cette application.", - "clients.connectWizard.dotnetSdkStep1": "Installer le SDK .NET", - "clients.connectWizard.dotnetSdkStep1Download": "Le SDK est disponible sur [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Version 14 et antérieure : Créer un gestionnaire de clientèle", - "clients.connectWizard.dotnetSdkStep2_15": "Version 15 et supérieures : Créer un client", - "clients.connectWizard.dotnetSdkStep3": "Facultatif\u00A0: installez les extensions de service pour le SDK", - "clients.connectWizard.dotnetSdkStep3Download": "L'extension SDK est disponible sur [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary.ServiceExtensions/)", - "clients.connectWizard.dotnetSdkStep4": "Facultativement\u00A0: Enregistrez le gestionnaire de clientèle et tous les clients", - "clients.connectWizard.javascriptSdk": "Utiliser le SDK JavaScript", - "clients.connectWizard.javascriptSdkDocumentation": "Les documentations pour le SDK JavaScript sont disponibles\u00A0:", - "clients.connectWizard.javascriptSdkHint": "Installez le SDK et établissez une connexion à cette application.", - "clients.connectWizard.javascriptSdkStep1": "Installer le SDK Javascript", - "clients.connectWizard.javascriptSdkStep1Download": "Le SDK est disponible sur [npm](https://www.npmjs.com/package/@squidex/squidex", - "clients.connectWizard.javascriptSdkStep2": "Créer un client", "clients.connectWizard.manually": "Connectez-vous manuellement", "clients.connectWizard.manuallyHint": "Obtenez des instructions pour établir une connexion avec Postman ou curl.", "clients.connectWizard.manuallyStep1": "Obtenir un jeton en utilisant curl", diff --git a/backend/i18n/source/frontend_it.json b/backend/i18n/source/frontend_it.json index c35828a46..ae80fa617 100644 --- a/backend/i18n/source/frontend_it.json +++ b/backend/i18n/source/frontend_it.json @@ -147,11 +147,6 @@ "clients.connectWizard.cliStep3": "Inserisci il nome della tua app per la configurazione della CLI", "clients.connectWizard.cliStep3Hint": "È possibile gestire le configurazione per le diverse appi all'interno della CLI e passare ad un'app.", "clients.connectWizard.cliStep4": "Passa alla tua app usando CLI", - "clients.connectWizard.dotnetSdk": "Connetti la tua APP utilizzando SDK", - "clients.connectWizard.dotnetSdkHint": "Scarica l'SDK e connetti quest'app.", - "clients.connectWizard.dotnetSdkStep1": "Installa .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "L'SDK è disponibile su [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Crea un client manager", "clients.connectWizard.manually": "Connetti manualmente", "clients.connectWizard.manuallyHint": "Leggi le istruzioni su come stabilire una connessione utilizzando Postman o curl.", "clients.connectWizard.manuallyStep1": "Ottenere un token usando curl", diff --git a/backend/i18n/source/frontend_nl.json b/backend/i18n/source/frontend_nl.json index 91c127ec5..21f5b879a 100644 --- a/backend/i18n/source/frontend_nl.json +++ b/backend/i18n/source/frontend_nl.json @@ -169,11 +169,6 @@ "clients.connectWizard.cliStep3": "Voeg uw app-naam toe aan de CLI-configuratie", "clients.connectWizard.cliStep3Hint": "Je kunt de configuratie voor meerdere apps in de CLI beheren en overschakelen naar een app.", "clients.connectWizard.cliStep4": "Schakel over naar uw app in de CLI", - "clients.connectWizard.dotnetSdk": "Maak verbinding met uw app met SDK", - "clients.connectWizard.dotnetSdkHint": "Download een SDK en maak verbinding met deze app.", - "clients.connectWizard.dotnetSdkStep1": "Installeer de .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "De SDK is beschikbaar op [nuget] (https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Maak een klantenbeheerder", "clients.connectWizard.manually": "Handmatig verbinden", "clients.connectWizard.manuallyHint": "Krijg instructies om een ​​verbinding tot stand te brengen met Postman of curl.", "clients.connectWizard.manuallyStep1": "Verkrijg een token met curl", diff --git a/backend/i18n/source/frontend_pt.json b/backend/i18n/source/frontend_pt.json index bd4e8c8db..b36461c14 100644 --- a/backend/i18n/source/frontend_pt.json +++ b/backend/i18n/source/frontend_pt.json @@ -180,11 +180,6 @@ "clients.connectWizard.cliStep3": "Adicione o nome da sua aplicação ao CLI config", "clients.connectWizard.cliStep3Hint": "Pode gerir a configuração de várias aplicações no CLI e mudar para uma aplicação.", "clients.connectWizard.cliStep4": "Mude para a sua aplicação no CLI", - "clients.connectWizard.dotnetSdk": "Conecte-se à sua App com a SDK", - "clients.connectWizard.dotnetSdkHint": "Descarregue um SDK e estabeleça uma ligação a esta aplicação.", - "clients.connectWizard.dotnetSdkStep1": "Instale o .NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "O SDK está disponível em [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "Criar um gestor de clientes", "clients.connectWizard.manually": "Conecte-se manualmente", "clients.connectWizard.manuallyHint": "Obtenha instruções sobre como estabelecer uma ligação com o Carteiro ou o caracol.", "clients.connectWizard.manuallyStep1": "Obter um símbolo usando caracóis", diff --git a/backend/i18n/source/frontend_zh.json b/backend/i18n/source/frontend_zh.json index 8d172325c..e518e8ee4 100644 --- a/backend/i18n/source/frontend_zh.json +++ b/backend/i18n/source/frontend_zh.json @@ -157,11 +157,6 @@ "clients.connectWizard.cliStep3": "在 CLI 配置中添加你的应用名称", "clients.connectWizard.cliStep3Hint": "您可以在 CLI 中管理多个应用程序的配置并切换到一个应用程序。", "clients.connectWizard.cliStep4": "在 CLI 中切换到您的应用程序", - "clients.connectWizard.dotnetSdk": "使用 SDK 连接到您的应用程序", - "clients.connectWizard.dotnetSdkHint": "下载 SDK 并建立与此应用程序的连接。", - "clients.connectWizard.dotnetSdkStep1": "安装.NET SDK", - "clients.connectWizard.dotnetSdkStep1Download": "SDK 可在 [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", - "clients.connectWizard.dotnetSdkStep2": "创建客户端管理器", "clients.connectWizard.manually": "手动连接", "clients.connectWizard.manuallyHint": "获取如何与 Postman 或 curl 建立连接的说明。", "clients.connectWizard.manuallyStep1": "使用 curl 获取令牌", diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index c70d2283c..f0454dfc4 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/frontend/src/app/features/content/shared/forms/chat-dialog.component.html b/frontend/src/app/features/content/shared/forms/chat-dialog.component.html index f130e3f29..0caa1f403 100644 --- a/frontend/src/app/features/content/shared/forms/chat-dialog.component.html +++ b/frontend/src/app/features/content/shared/forms/chat-dialog.component.html @@ -1,17 +1,84 @@ - + {{ 'chat.title' | sqxTranslate }} - - - +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ {{item.prompt}} +
+
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+ {{ 'chat.answer' | sqxTranslate}} +
+ + +
+ +
+
+
+
+
+ +
+
+
+ +
+
+
+
+ + + + + +
+
+
+
+ +
-
- - - -

{{ 'chat.answers' | sqxTranslate }}

- -
- {{ 'chat.answersEmpty' | sqxTranslate }} -
- -
-
- -
-
- -
-
-
-
- - -
- -
-
diff --git a/frontend/src/app/features/content/shared/forms/chat-dialog.component.scss b/frontend/src/app/features/content/shared/forms/chat-dialog.component.scss index 573bc47d6..31ccba692 100644 --- a/frontend/src/app/features/content/shared/forms/chat-dialog.component.scss +++ b/frontend/src/app/features/content/shared/forms/chat-dialog.component.scss @@ -1,6 +1,66 @@ @import 'mixins'; @import 'vars'; +:host ::ng-deep { + .modal-body { + background-color: $color-background; + } +} + +form { + width: 100%; +} + textarea { height: 300px; +} + +.flex-reverse { + flex-direction: row-reverse; +} + +.bubble { + background-color: $color-white; + border: 0; + border-radius: $border-radius; + padding: 1rem; + position: relative; + + &-right { + &::before { + @include caret-left($color-white, 10px); + @include absolute(.5rem, null, null, -18px); + } + } + + &-left { + &::before { + @include caret-right($color-white, 10px); + @include absolute(.5rem, -18px); + } + } +} + +@keyframes blink { + 50% { + fill: transparent + } +} + +.dot { + animation: 1s blink infinite; +} + +svg { + .dot { + fill: $color-border; + } +} + +.dot:nth-child(2) { + animation-delay: 250ms; +} + +.dot:nth-child(3) { + animation-delay: 500ms; } \ No newline at end of file diff --git a/frontend/src/app/features/content/shared/forms/chat-dialog.component.ts b/frontend/src/app/features/content/shared/forms/chat-dialog.component.ts index b0aff8729..40c1d6511 100644 --- a/frontend/src/app/features/content/shared/forms/chat-dialog.component.ts +++ b/frontend/src/app/features/content/shared/forms/chat-dialog.component.ts @@ -5,8 +5,8 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Component, EventEmitter, Output } from '@angular/core'; -import { AppsState, StatefulComponent, TranslationsService } from '@app/shared'; +import { Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core'; +import { AppsState, AuthService, StatefulComponent, TranslationsService } from '@app/shared'; interface State { // True, when running @@ -16,7 +16,7 @@ interface State { chatQuestion: string; // The answers. - chatAnswers?: ReadonlyArray; + chatTalk: ReadonlyArray<{ prompt: string; isUser?: boolean }>; } @Component({ @@ -31,14 +31,20 @@ export class ChatDialogComponent extends StatefulComponent { @Output() public select = new EventEmitter(); + @ViewChild('input', { static: false }) + public input!: ElementRef; + + public user = this.authService.user!; + constructor( private readonly appsState: AppsState, + private readonly authService: AuthService, private readonly translator: TranslationsService, ) { super({ isRunning: false, chatQuestion: '', - chatAnswers: undefined, + chatTalk: [], }); } @@ -47,15 +53,40 @@ export class ChatDialogComponent extends StatefulComponent { } public ask() { - this.next({ isRunning: true }); + const prompt = this.snapshot.chatQuestion; - this.translator.ask(this.appsState.appName, { prompt: this.snapshot.chatQuestion }) + if (!prompt || prompt.length === 0) { + return; + } + + this.next(s => ({ + ...s, + chatQuestion: '', + chatTalk: [ + ...s.chatTalk, + { prompt, isUser: true }, + ], + isRunning: true, + })); + + this.translator.ask(this.appsState.appName, { prompt }) .subscribe({ next: chatAnswers => { - this.next({ chatAnswers, isRunning: false }); + this.next(s => ({ + ...s, + chatTalk: [ + ...s.chatTalk, + ...chatAnswers.map(answer => ({ prompt: answer })), + ], + isRunning: false, + })); + + setTimeout(() => { + this.input.nativeElement.focus(); + }, 100); }, error: () => { - this.next({ chatAnswers: [], isRunning: false }); + this.next({ isRunning: false }); }, complete: () => { this.next({ isRunning: false }); diff --git a/frontend/src/app/features/content/shared/forms/field-editor.component.ts b/frontend/src/app/features/content/shared/forms/field-editor.component.ts index 36cc8f023..892fbc2ad 100644 --- a/frontend/src/app/features/content/shared/forms/field-editor.component.ts +++ b/frontend/src/app/features/content/shared/forms/field-editor.component.ts @@ -57,7 +57,7 @@ export class FieldEditorComponent { public isEmpty?: Observable; public isExpanded = false; - public chatDialog = new DialogModel(); + public chatDialog = new DialogModel(true); public get field() { return this.formModel.field; diff --git a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html index 4f4ba0db0..72ec79bbe 100644 --- a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html +++ b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html @@ -9,7 +9,7 @@ - + - @@ -54,18 +54,10 @@
-
-
{{ 'clients.connectWizard.dotnetSdk' | sqxTranslate }}
+
+
{{ 'clients.connectWizard.sdk' | sqxTranslate }}
- {{ 'clients.connectWizard.dotnetSdkHint' | sqxTranslate }} - - -
- -
-
{{ 'clients.connectWizard.javascriptSdk' | sqxTranslate }}
- - {{ 'clients.connectWizard.javascriptSdkHint' | sqxTranslate }} + {{ 'clients.connectWizard.sdkHint' | sqxTranslate }}
@@ -144,132 +136,35 @@

- -
- - {{ 'clients.connectWizard.dotnetSdkDocumentation' | sqxTranslate }} {{ 'common.documentation' | sqxTranslate }} - -
- -
-
1 {{ 'clients.connectWizard.dotnetSdkStep1' | sqxTranslate }}
- -
- -

- dotnet add package Squidex.ClientLibrary -

-
- -
-
2 {{ 'clients.connectWizard.dotnetSdkStep2' | sqxTranslate }}
- -

- -

using Squidex.ClientLibrary;
-
 
-
var clientManager = new SquidexClientManager(new SquidexOptions
-
{{'{'}}
-
AppName = "{{appName}}",
-
ClientId = "{{appName}}:{{client.id}}",
-
ClientSecret = "{{client.secret}}",
-
Url = "{{apiUrl.value}}"
-
});
- -

-
- -
-
2 {{ 'clients.connectWizard.dotnetSdkStep2_15' | sqxTranslate }}
- -

- -

using Squidex.ClientLibrary;
-
 
-
var client = new SquidexClient(new SquidexOptions
-
{{'{'}}
-
AppName = "{{appName}}",
-
ClientId = "{{appName}}:{{client.id}},
-
ClientSecret = "{{client.secret}}",
-
Url = "{{apiUrl.value}}"
-
});
- -

-
- -
-
3 {{ 'clients.connectWizard.dotnetSdkStep3' | sqxTranslate }}
- -
- -

- dotnet add package Squidex.ClientLibrary.ServiceExtensions -

+ +
+
+ + {{availableSDK.value.name}} +
-
-
4 {{ 'clients.connectWizard.dotnetSdkStep4' | sqxTranslate }}
+
+ -

- -

using Microsoft.Extensions.DependencyInjection;
-
 
-
services.AddSquidex(options =>
-
{{'{'}}
-
options.AppName = "{{appName}}";
-
options.ClientId = "{{appName}}:{{client.id}}";
-
options.ClientSecret = "{{client.secret}}";
-
options.Url = "{{apiUrl.value}}";
-
});
- -

+
-
+
{{ 'clients.connectWizard.sdkHelp' | sqxTranslate }} {{ 'clients.connectWizard.sdkHelpLink' | sqxTranslate }}
- -
- - {{ 'clients.connectWizard.javascriptSdkDocumentation' | sqxTranslate }} {{ 'common.documentation' | sqxTranslate }} - -
- -
-
1 {{ 'clients.connectWizard.javascriptSdkStep1' | sqxTranslate }}
- -
- -

- npm i @squidex/squidex --save -

-
- -
-
2 {{ 'clients.connectWizard.javascriptSdkStep2' | sqxTranslate }}
- -

- -

import {{'{'}} SquidexClient } from "@squidex/squidex";
-
 
-
const client = new SquidexClient({{'{'}}
-
appName: "{{appName}}",
-
clientId: "{{appName}}:{{client.id}}",
-
clientSecret: "{{client.secret}}",
-
environment: "{{apiUrl.value}}"
-
});
- -

-
-
- diff --git a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.scss b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.scss index 9bf1100f4..255463ba6 100644 --- a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.scss +++ b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.scss @@ -1,6 +1,26 @@ @import 'mixins'; @import 'vars'; +sqx-code { + pre { + white-space: pre; + } +} + +:host ::ng-deep { + svg { + max-height: 100%; + } + + h3 { + margin-top: 1.75rem; + } + + .code-container { + margin: .5rem 0; + } +} + .badge { @include circle(1.3rem); font-size: $font-smallest; @@ -23,6 +43,30 @@ } } +.sdk-header { + border: 1px solid $color-border; + border-radius: $border-radius; + display: inline-block; + cursor: pointer; + padding: 1rem; + margin-bottom: .5rem; + margin-right: .5rem; + width: 160px; + text-align: center; + + &.active { + border-color: $color-theme-brand; + } + + &:hover { + border-color: $color-theme-brand-dark; + } + + .logo { + height: 100px; + } +} + .option { background: none; border: 1px solid $color-border; @@ -43,10 +87,4 @@ font-size: $font-smallest; font-weight: normal; } -} - -sqx-code { - pre { - white-space: pre; - } } \ No newline at end of file diff --git a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.ts b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.ts index 35d583ade..863c854e3 100644 --- a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.ts +++ b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.ts @@ -6,7 +6,7 @@ */ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { AccessTokenDto, ApiUrlConfig, AppsState, ClientDto, ClientsService, ClientTourStated, DialogService, MessageBus } from '@app/shared'; +import { AccessTokenDto, ApiUrlConfig, AppsState, ClientDto, ClientsService, ClientTourStated, DialogService, HelpService, MessageBus, SDKEntry } from '@app/shared'; @Component({ selector: 'sqx-client-connect-form', @@ -20,21 +20,21 @@ export class ClientConnectFormComponent implements OnInit { @Input({ required: true }) public client!: ClientDto; + public sdks = this.helpService.getSDKs(); + public sdk?: SDKEntry; + public appName!: string; public appToken?: AccessTokenDto; public step = 'Start'; - public get isStart() { - return this.step === 'Start'; - } - constructor( public readonly appsState: AppsState, public readonly apiUrl: ApiUrlConfig, private readonly changeDetector: ChangeDetectorRef, private readonly clientsService: ClientsService, private readonly dialogs: DialogService, + private readonly helpService: HelpService, private readonly messageBus: MessageBus, ) { } @@ -57,6 +57,15 @@ export class ClientConnectFormComponent implements OnInit { this.messageBus.emit(new ClientTourStated()); } + public select(sdk: SDKEntry) { + sdk.instructions = sdk.instructions.replace(//g, this.appName); + sdk.instructions = sdk.instructions.replace(//g, `${this.appName}:${this.client.id}`); + sdk.instructions = sdk.instructions.replace(//g, this.client.secret); + sdk.instructions = sdk.instructions.replace(//g, this.apiUrl.value); + + this.sdk = sdk; + } + public go(step: string) { this.step = step; } diff --git a/frontend/src/app/features/settings/pages/clients/client.component.ts b/frontend/src/app/features/settings/pages/clients/client.component.ts index 6ef18c945..c356f014a 100644 --- a/frontend/src/app/features/settings/pages/clients/client.component.ts +++ b/frontend/src/app/features/settings/pages/clients/client.component.ts @@ -23,7 +23,7 @@ export class ClientComponent { public apiCallsLimit = 0; - public connectDialog = new DialogModel(); + public connectDialog = new DialogModel(false); constructor( public readonly appsState: AppsState, diff --git a/frontend/src/app/framework/angular/code.component.html b/frontend/src/app/framework/angular/code.component.html index dd797f9dc..64f56826e 100644 --- a/frontend/src/app/framework/angular/code.component.html +++ b/frontend/src/app/framework/angular/code.component.html @@ -1,7 +1,7 @@ -
- -
+
\ No newline at end of file diff --git a/frontend/src/app/framework/angular/code.component.scss b/frontend/src/app/framework/angular/code.component.scss index b7cb6a2ab..2742d895e 100644 --- a/frontend/src/app/framework/angular/code.component.scss +++ b/frontend/src/app/framework/angular/code.component.scss @@ -1,34 +1,2 @@ @import 'mixins'; -@import 'vars'; - -.code { - background: $color-code-background; - margin: .25rem 0; - padding-left: .5rem; - padding-right: 3rem; -} - -.code, -.code-copy { - @include text-code; - min-height: 27px; - padding-bottom: .25rem; - padding-top: .25rem; -} - -.copy-container { - position: relative; -} - -.code-copy { - @include absolute(0, 0, auto, auto); - background: darken($color-border-dark, 30%); - border: 0; - color: $color-white; - padding-left: .375rem; - padding-right: .375rem; - - &:focus { - background: darken($color-border-dark, 40%); - } -} \ No newline at end of file +@import 'vars'; \ No newline at end of file diff --git a/frontend/src/app/framework/angular/code.component.ts b/frontend/src/app/framework/angular/code.component.ts index 5d1bf4108..2cb1318a7 100644 --- a/frontend/src/app/framework/angular/code.component.ts +++ b/frontend/src/app/framework/angular/code.component.ts @@ -6,6 +6,7 @@ */ import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { MathHelper } from '../internal'; @Component({ selector: 'sqx-code', @@ -13,4 +14,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; templateUrl: './code.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class CodeComponent {} +export class CodeComponent { + public readonly id = MathHelper.guid(); +} diff --git a/frontend/src/app/framework/angular/forms/copy-global.directive.ts b/frontend/src/app/framework/angular/forms/copy-global.directive.ts new file mode 100644 index 000000000..f668e4388 --- /dev/null +++ b/frontend/src/app/framework/angular/forms/copy-global.directive.ts @@ -0,0 +1,91 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { Directive, HostListener, Renderer2 } from '@angular/core'; +import { DialogService, Types } from '@app/framework/internal'; + +@Directive({ + selector: '[sqxCopyGlobal]', +}) +export class CopyGlobalDirective { + constructor( + private readonly dialogs: DialogService, + private readonly renderer: Renderer2, + ) { + } + + @HostListener('document:click', ['$event']) + public onClick(event: MouseEvent) { + function findElement(target: HTMLElement | null): string | null { + if (!target) { + return null; + } + + const id = target.getAttribute('copy')!; + + if (id) { + return id; + } + + return findElement(target.parentElement); + } + + const toCopy = document.getElementById(findElement(event.target as any)!); + + if (!toCopy) { + return; + } + + this.copyToClipbord(toCopy); + } + + private copyToClipbord(element: HTMLElement) { + if (Types.is(element, HTMLInputElement) || Types.is(element, HTMLTextAreaElement)) { + const currentFocus: any = document.activeElement; + + const prevSelectionStart = element.selectionStart; + const prevSelectionEnd = element.selectionEnd; + + element.focus(); + element.setSelectionRange(0, element.value.length); + + this.copy(); + + element.setSelectionRange(prevSelectionStart!, prevSelectionEnd!); + + if (currentFocus && Types.isFunction(currentFocus.focus)) { + currentFocus.focus(); + } + } else { + const input = this.renderer.createElement('textarea'); + + this.renderer.setStyle(input, 'position', 'absolute'); + this.renderer.setStyle(input, 'right', '-1000px'); + this.renderer.appendChild(document.body, input); + + input.value = element.innerText; + input.select(); + + this.copy(); + + this.renderer.removeChild(document.body, input); + } + } + + private copy() { + try { + // eslint-disable-next-line deprecation/deprecation + document.execCommand('copy'); + + this.dialogs.notifyInfo('i18n:common.clipboardAdded'); + + return true; + } catch (e) { + return false; + } + } +} diff --git a/frontend/src/app/framework/angular/markdown.directive.ts b/frontend/src/app/framework/angular/markdown.directive.ts index 54ab21a30..77e48b071 100644 --- a/frontend/src/app/framework/angular/markdown.directive.ts +++ b/frontend/src/app/framework/angular/markdown.directive.ts @@ -15,6 +15,9 @@ export class MarkdownDirective { @Input('sqxMarkdown') public markdown!: string; + @Input({ transform: booleanAttribute }) + public trusted = false; + @Input({ transform: booleanAttribute }) public inline = true; @@ -43,7 +46,7 @@ export class MarkdownDirective { } else if (this.optional && !hasExclamation) { html = markdown; } else if (this.markdown) { - html = renderMarkdown(markdown, this.inline); + html = renderMarkdown(markdown, this.inline, this.trusted); } const hasHtml = html.indexOf('<') >= 0 || html.indexOf('&') >= 0; diff --git a/frontend/src/app/framework/declarations.ts b/frontend/src/app/framework/declarations.ts index c83e476d9..2962ec7c2 100644 --- a/frontend/src/app/framework/declarations.ts +++ b/frontend/src/app/framework/declarations.ts @@ -14,6 +14,7 @@ export * from './angular/forms/confirm-click.directive'; export * from './angular/forms/control-errors-messages.component'; export * from './angular/forms/control-errors.component'; export * from './angular/forms/copy.directive'; +export * from './angular/forms/copy-global.directive'; export * from './angular/forms/editable-title.component'; export * from './angular/forms/editors/autocomplete.component'; export * from './angular/forms/editors/checkbox-group.component'; diff --git a/frontend/src/app/framework/module.ts b/frontend/src/app/framework/module.ts index 08b760227..1af43c185 100644 --- a/frontend/src/app/framework/module.ts +++ b/frontend/src/app/framework/module.ts @@ -12,7 +12,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { ColorPickerModule } from 'ngx-color-picker'; import { TourService as BaseTourService } from 'ngx-ui-tour-core'; -import { AnalyticsService, AutocompleteComponent, AvatarComponent, CachingInterceptor, CanDeactivateGuard, CheckboxGroupComponent, ClipboardService, CodeComponent, CodeEditorComponent, ColorPickerComponent, CompensateScrollbarDirective, ConfirmClickDirective, ControlErrorsComponent, ControlErrorsMessagesComponent, CopyDirective, DarkenPipe, DatePipe, DateTimeEditorComponent, DayOfWeekPipe, DayPipe, DialogRendererComponent, DialogService, DisplayNamePipe, DropdownComponent, DropdownMenuComponent, DurationPipe, EditableTitleComponent, ExternalLinkDirective, FileDropDirective, FileSizePipe, FocusOnInitDirective, FormAlertComponent, FormErrorComponent, FormHintComponent, FromNowPipe, FullDateTimePipe, GlobalErrorHandler, HighlightPipe, HoverBackgroundDirective, IfOnceDirective, ImageSourceDirective, ImageUrlDirective, IndeterminateValueDirective, ISODatePipe, JoinPipe, KeysPipe, KNumberPipe, LanguageSelectorComponent, LayoutComponent, LayoutContainerDirective, LightenPipe, ListViewComponent, LoaderComponent, LoadingInterceptor, LoadingService, LocalizedInputComponent, LocalStoreService, LongHoverDirective, MarkdownDirective, MarkdownInlinePipe, MarkdownPipe, MessageBus, ModalDialogComponent, ModalDirective, ModalPlacementDirective, MonthPipe, PagerComponent, ParentLinkDirective, ProgressBarComponent, RadioGroupComponent, ResizedDirective, ResizeService, ResourceLoaderService, RootViewComponent, SafeHtmlPipe, SafeResourceUrlPipe, SafeUrlPipe, ScrollActiveDirective, ShortcutComponent, ShortcutDirective, ShortcutService, ShortDatePipe, ShortTimePipe, StarsComponent, StatusIconComponent, StopClickDirective, StopDragDirective, SyncScollingDirective, SyncWidthDirective, TabRouterlinkDirective, TagEditorComponent, TemplateWrapperDirective, TempService, TitleComponent, TitleService, ToggleComponent, ToolbarComponent, TooltipDirective, TourService, TourStepDirective, TourTemplateComponent, TransformInputDirective, TranslatePipe, VideoPlayerComponent } from './declarations'; +import { AnalyticsService, AutocompleteComponent, AvatarComponent, CachingInterceptor, CanDeactivateGuard, CheckboxGroupComponent, ClipboardService, CodeComponent, CodeEditorComponent, ColorPickerComponent, CompensateScrollbarDirective, ConfirmClickDirective, ControlErrorsComponent, ControlErrorsMessagesComponent, CopyDirective, CopyGlobalDirective, DarkenPipe, DatePipe, DateTimeEditorComponent, DayOfWeekPipe, DayPipe, DialogRendererComponent, DialogService, DisplayNamePipe, DropdownComponent, DropdownMenuComponent, DurationPipe, EditableTitleComponent, ExternalLinkDirective, FileDropDirective, FileSizePipe, FocusOnInitDirective, FormAlertComponent, FormErrorComponent, FormHintComponent, FromNowPipe, FullDateTimePipe, GlobalErrorHandler, HighlightPipe, HoverBackgroundDirective, IfOnceDirective, ImageSourceDirective, ImageUrlDirective, IndeterminateValueDirective, ISODatePipe, JoinPipe, KeysPipe, KNumberPipe, LanguageSelectorComponent, LayoutComponent, LayoutContainerDirective, LightenPipe, ListViewComponent, LoaderComponent, LoadingInterceptor, LoadingService, LocalizedInputComponent, LocalStoreService, LongHoverDirective, MarkdownDirective, MarkdownInlinePipe, MarkdownPipe, MessageBus, ModalDialogComponent, ModalDirective, ModalPlacementDirective, MonthPipe, PagerComponent, ParentLinkDirective, ProgressBarComponent, RadioGroupComponent, ResizedDirective, ResizeService, ResourceLoaderService, RootViewComponent, SafeHtmlPipe, SafeResourceUrlPipe, SafeUrlPipe, ScrollActiveDirective, ShortcutComponent, ShortcutDirective, ShortcutService, ShortDatePipe, ShortTimePipe, StarsComponent, StatusIconComponent, StopClickDirective, StopDragDirective, SyncScollingDirective, SyncWidthDirective, TabRouterlinkDirective, TagEditorComponent, TemplateWrapperDirective, TempService, TitleComponent, TitleService, ToggleComponent, ToolbarComponent, TooltipDirective, TourService, TourStepDirective, TourTemplateComponent, TransformInputDirective, TranslatePipe, VideoPlayerComponent } from './declarations'; @NgModule({ imports: [ @@ -34,6 +34,7 @@ import { AnalyticsService, AutocompleteComponent, AvatarComponent, CachingInterc ControlErrorsComponent, ControlErrorsMessagesComponent, CopyDirective, + CopyGlobalDirective, DarkenPipe, DatePipe, DateTimeEditorComponent, @@ -124,6 +125,7 @@ import { AnalyticsService, AutocompleteComponent, AvatarComponent, CachingInterc ConfirmClickDirective, ControlErrorsComponent, CopyDirective, + CopyGlobalDirective, DarkenPipe, DatePipe, DateTimeEditorComponent, diff --git a/frontend/src/app/framework/utils/markdown.ts b/frontend/src/app/framework/utils/markdown.ts index c6bb9a851..1d1b86230 100644 --- a/frontend/src/app/framework/utils/markdown.ts +++ b/frontend/src/app/framework/utils/markdown.ts @@ -6,6 +6,7 @@ */ import { marked } from 'marked'; +import { MathHelper } from './math-helper'; function renderLink(href: string, _: string, text: string) { if (href && href.startsWith('mailto')) { @@ -15,6 +16,20 @@ function renderLink(href: string, _: string, text: string) { } } +function renderCode(code: string) { + const id = MathHelper.guid(); + + return ` +
+ + +
${code}
+
+ `; +} + function renderInlineParagraph(text: string) { return text; } @@ -24,14 +39,18 @@ const RENDERER_INLINE = new marked.Renderer(); RENDERER_INLINE.paragraph = renderInlineParagraph; RENDERER_INLINE.link = renderLink; +RENDERER_INLINE.code = renderCode; RENDERER_DEFAULT.link = renderLink; +RENDERER_DEFAULT.code = renderCode; -export function renderMarkdown(input: string | undefined | null, inline: boolean) { +export function renderMarkdown(input: string | undefined | null, inline: boolean, trusted = false) { if (!input) { return ''; } - input = escapeHTML(input); + if (!trusted) { + input = escapeHTML(input); + } if (inline) { return marked(input, { renderer: RENDERER_INLINE, mangle: false, headerIds: false }); diff --git a/frontend/src/app/shared/services/help.service.spec.ts b/frontend/src/app/shared/services/help.service.spec.ts index a9183f8d2..98403102c 100644 --- a/frontend/src/app/shared/services/help.service.spec.ts +++ b/frontend/src/app/shared/services/help.service.spec.ts @@ -9,7 +9,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; -import { HelpService } from '@app/shared/internal'; +import { HelpService, SDKEntry } from '@app/shared/internal'; describe('HelpService', () => { beforeEach(() => { @@ -62,4 +62,44 @@ describe('HelpService', () => { expect(helpSections!).toEqual(''); })); + + it('should make get request to get sdks', + inject([HelpService, HttpTestingController], (helpService: HelpService, httpMock: HttpTestingController) => { + let sdks: Record; + + helpService.getSDKs().subscribe(result => { + sdks = result; + }); + + const req = httpMock.expectOne('https://raw.githubusercontent.com/Squidex/sdk-fern/main/sdks.json'); + + expect(req.request.method).toEqual('GET'); + expect(req.request.headers.get('If-Match')).toBeNull(); + + req.flush({ + dotnet: {}, + }); + + expect(sdks!).toEqual({ + dotnet: {} as any, + }); + })); + + it('should return empty sdks if get request fails', + inject([HelpService, HttpTestingController], (helpService: HelpService, httpMock: HttpTestingController) => { + let sdks: Record; + + helpService.getSDKs().subscribe(result => { + sdks = result; + }); + + const req = httpMock.expectOne('https://raw.githubusercontent.com/Squidex/sdk-fern/main/sdks.json'); + + expect(req.request.method).toEqual('GET'); + expect(req.request.headers.get('If-Match')).toBeNull(); + + req.error({}); + + expect(sdks!).toEqual({}); + })); }); diff --git a/frontend/src/app/shared/services/help.service.ts b/frontend/src/app/shared/services/help.service.ts index c42cb6c9b..1bc0c0d7c 100644 --- a/frontend/src/app/shared/services/help.service.ts +++ b/frontend/src/app/shared/services/help.service.ts @@ -10,6 +10,23 @@ import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { catchError } from 'rxjs/operators'; +export interface SDKEntry { + // The display name. + name: string; + + // The link to the repository. + repository: string; + + // The link to the documentation. + documentation: string; + + // The instructions as markdown. + instructions: string; + + // The SVG logo. + logo: string; +} + @Injectable() export class HelpService { constructor( @@ -23,4 +40,11 @@ export class HelpService { return this.http.get(url, { responseType: 'text' }).pipe( catchError(() => of(''))); } + + public getSDKs(): Observable> { + const url = 'https://raw.githubusercontent.com/Squidex/sdk-fern/main/sdks.json'; + + return this.http.get>(url).pipe( + catchError(() => of({}))); + } } diff --git a/frontend/src/app/theme/_common.scss b/frontend/src/app/theme/_common.scss index dca2b684e..74b6c6727 100644 --- a/frontend/src/app/theme/_common.scss +++ b/frontend/src/app/theme/_common.scss @@ -154,6 +154,40 @@ hr { } } +// +// Code +// +.code { + background: $color-code-background; + margin: .25rem 0; + padding-left: .5rem; + padding-right: 3rem; +} +.code, +.code-copy { + @include text-code; + min-height: 27px; + padding-bottom: .25rem; + padding-top: .25rem; +} + +.code-container { + position: relative; +} + +.code-copy { + @include absolute(0, 0, auto, auto); + background: darken($color-border-dark, 30%); + border: 0; + color: $color-white; + padding-left: .375rem; + padding-right: .375rem; + + &:focus { + background: darken($color-border-dark, 40%); + } +} + // // Profile picture in circle // @@ -187,6 +221,10 @@ hr { img { max-height: 70%; } + + &-sm { + @include circle(32px); + } } .ngx-ui-tour_backdrop {