Browse Source

Improve chat dialog and connect form

* Fix chat dialog and connect form.

* Fix trusted flag
pull/1023/head
Sebastian Stehle 3 years ago
committed by GitHub
parent
commit
d778c17bce
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      backend/i18n/frontend_en.json
  2. 26
      backend/i18n/frontend_fr.json
  3. 14
      backend/i18n/frontend_it.json
  4. 14
      backend/i18n/frontend_nl.json
  5. 14
      backend/i18n/frontend_pt.json
  6. 14
      backend/i18n/frontend_zh.json
  7. 14
      backend/i18n/source/frontend_en.json
  8. 16
      backend/i18n/source/frontend_fr.json
  9. 5
      backend/i18n/source/frontend_it.json
  10. 5
      backend/i18n/source/frontend_nl.json
  11. 5
      backend/i18n/source/frontend_pt.json
  12. 5
      backend/i18n/source/frontend_zh.json
  13. 2
      frontend/src/app/app.component.html
  14. 104
      frontend/src/app/features/content/shared/forms/chat-dialog.component.html
  15. 60
      frontend/src/app/features/content/shared/forms/chat-dialog.component.scss
  16. 47
      frontend/src/app/features/content/shared/forms/chat-dialog.component.ts
  17. 2
      frontend/src/app/features/content/shared/forms/field-editor.component.ts
  18. 145
      frontend/src/app/features/settings/pages/clients/client-connect-form.component.html
  19. 50
      frontend/src/app/features/settings/pages/clients/client-connect-form.component.scss
  20. 19
      frontend/src/app/features/settings/pages/clients/client-connect-form.component.ts
  21. 2
      frontend/src/app/features/settings/pages/clients/client.component.ts
  22. 6
      frontend/src/app/framework/angular/code.component.html
  23. 34
      frontend/src/app/framework/angular/code.component.scss
  24. 5
      frontend/src/app/framework/angular/code.component.ts
  25. 91
      frontend/src/app/framework/angular/forms/copy-global.directive.ts
  26. 5
      frontend/src/app/framework/angular/markdown.directive.ts
  27. 1
      frontend/src/app/framework/declarations.ts
  28. 4
      frontend/src/app/framework/module.ts
  29. 23
      frontend/src/app/framework/utils/markdown.ts
  30. 42
      frontend/src/app/shared/services/help.service.spec.ts
  31. 24
      frontend/src/app/shared/services/help.service.ts
  32. 38
      frontend/src/app/theme/_common.scss

14
backend/i18n/frontend_en.json

@ -166,6 +166,7 @@
"backups.started": "Backup started, it can take several minutes to complete.", "backups.started": "Backup started, it can take several minutes to complete.",
"backups.startedLabel": "Started", "backups.startedLabel": "Started",
"backups.startFailed": "Failed to start backup.", "backups.startFailed": "Failed to start backup.",
"chat.answer": "Here is my answer:",
"chat.answers": "Answers", "chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
@ -194,16 +195,6 @@
"clients.connectWizard.cliStep3": "Add your app name the CLI config", "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.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.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.javascriptSdk": "Use the JavaScript SDK",
"clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "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.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.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.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.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.sdkHelp": "You need another SDK?",
"clients.connectWizard.sdkHelpLink": "Contact us in the Support Forum", "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.step0Title": "Setup client",
"clients.connectWizard.step1Title": "Choose connection method", "clients.connectWizard.step1Title": "Choose connection method",
"clients.connectWizard.step2Title": "Connect", "clients.connectWizard.step2Title": "Connect",
@ -387,6 +380,7 @@
"common.remember": "Don't ask again", "common.remember": "Don't ask again",
"common.rename": "Rename", "common.rename": "Rename",
"common.renameTag": "Rename Tag", "common.renameTag": "Rename Tag",
"common.repository": "Repository",
"common.requiredHint": "required", "common.requiredHint": "required",
"common.reset": "Reset", "common.reset": "Reset",
"common.restore": "Restore", "common.restore": "Restore",

26
backend/i18n/frontend_fr.json

@ -166,6 +166,7 @@
"backups.started": "La sauvegarde a commencé, cela peut prendre plusieurs minutes.", "backups.started": "La sauvegarde a commencé, cela peut prendre plusieurs minutes.",
"backups.startedLabel": "Commencé", "backups.startedLabel": "Commencé",
"backups.startFailed": "Échec du démarrage de la sauvegarde.", "backups.startFailed": "Échec du démarrage de la sauvegarde.",
"chat.answer": "Here is my answer:",
"chat.answers": "Answers", "chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
@ -194,22 +195,12 @@
"clients.connectWizard.cliStep3": "Ajoutez le nom de votre application à la configuration CLI", "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.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.cliStep4": "Basculez vers votre application dans la CLI",
"clients.connectWizard.dotnetSdk": "Utiliser le SDK .NET", "clients.connectWizard.javascriptSdk": "Use the JavaScript SDK",
"clients.connectWizard.dotnetSdkDocumentation": "Les documentations pour le SDK .NET sont disponibles\u00A0:", "clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ",
"clients.connectWizard.dotnetSdkHint": "Installez le SDK .NET et établissez une connexion à cette application.", "clients.connectWizard.javascriptSdkHint": "Install the SDK and establish a connection to this app.",
"clients.connectWizard.dotnetSdkStep1": "Installer le SDK .NET", "clients.connectWizard.javascriptSdkStep1": "Install the Javascript SDK",
"clients.connectWizard.dotnetSdkStep1Download": "Le SDK est disponible sur [nuget](https://www.nuget.org/packages/Squidex.ClientLibrary/)", "clients.connectWizard.javascriptSdkStep1Download": "The SDK is available on [npm](https://www.npmjs.com/package/@squidex/squidex)",
"clients.connectWizard.dotnetSdkStep2": "Version 14 et antérieure : Créer un gestionnaire de clientèle", "clients.connectWizard.javascriptSdkStep2": "Create a client",
"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.manually": "Connectez-vous manuellement",
"clients.connectWizard.manuallyHint": "Obtenez des instructions pour établir une connexion avec Postman ou curl.", "clients.connectWizard.manuallyHint": "Obtenez des instructions pour établir une connexion avec Postman ou curl.",
"clients.connectWizard.manuallyStep1": "Obtenir un jeton en utilisant 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.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.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.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.sdkHelp": "Vous avez besoin d'un autre SDK\u00A0?",
"clients.connectWizard.sdkHelpLink": "Contactez-nous sur le forum d'assistance", "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.step0Title": "Configurer le client",
"clients.connectWizard.step1Title": "Choisissez la méthode de connexion", "clients.connectWizard.step1Title": "Choisissez la méthode de connexion",
"clients.connectWizard.step2Title": "Connecter", "clients.connectWizard.step2Title": "Connecter",
@ -387,6 +380,7 @@
"common.remember": "Ne demande plus", "common.remember": "Ne demande plus",
"common.rename": "Renommer", "common.rename": "Renommer",
"common.renameTag": "Renommer la balise", "common.renameTag": "Renommer la balise",
"common.repository": "Repository",
"common.requiredHint": "requis", "common.requiredHint": "requis",
"common.reset": "Réinitialiser", "common.reset": "Réinitialiser",
"common.restore": "Restaurer", "common.restore": "Restaurer",

14
backend/i18n/frontend_it.json

@ -166,6 +166,7 @@
"backups.started": "Backup avviato, il suo completamento potrebbe richiedere alcuni minuti.", "backups.started": "Backup avviato, il suo completamento potrebbe richiedere alcuni minuti.",
"backups.startedLabel": "Avviato", "backups.startedLabel": "Avviato",
"backups.startFailed": "Non è stato possibile avviare il backup.", "backups.startFailed": "Non è stato possibile avviare il backup.",
"chat.answer": "Here is my answer:",
"chat.answers": "Answers", "chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
@ -194,16 +195,6 @@
"clients.connectWizard.cliStep3": "Inserisci il nome della tua app per la configurazione della CLI", "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.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.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.javascriptSdk": "Use the JavaScript SDK",
"clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "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.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.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.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.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.sdkHelp": "Hai bisogno di un altro SDK?",
"clients.connectWizard.sdkHelpLink": "Contattaci nel Forum di assistenza", "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.step0Title": "Setup client",
"clients.connectWizard.step1Title": "Scegli la tipologia di connessione", "clients.connectWizard.step1Title": "Scegli la tipologia di connessione",
"clients.connectWizard.step2Title": "Collega", "clients.connectWizard.step2Title": "Collega",
@ -387,6 +380,7 @@
"common.remember": "Ricorda la mia decisione", "common.remember": "Ricorda la mia decisione",
"common.rename": "Rinomina", "common.rename": "Rinomina",
"common.renameTag": "Rename Tag", "common.renameTag": "Rename Tag",
"common.repository": "Repository",
"common.requiredHint": "obbligatorio", "common.requiredHint": "obbligatorio",
"common.reset": "Reimposta", "common.reset": "Reimposta",
"common.restore": "Ripristina", "common.restore": "Ripristina",

14
backend/i18n/frontend_nl.json

@ -166,6 +166,7 @@
"backups.started": "Back-up gestart, het kan enkele minuten duren om te voltooien.", "backups.started": "Back-up gestart, het kan enkele minuten duren om te voltooien.",
"backups.startedLabel": "Gestart", "backups.startedLabel": "Gestart",
"backups.startFailed": "Starten van back-up is mislukt.", "backups.startFailed": "Starten van back-up is mislukt.",
"chat.answer": "Here is my answer:",
"chat.answers": "Answers", "chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
@ -194,16 +195,6 @@
"clients.connectWizard.cliStep3": "Voeg uw app-naam toe aan de CLI-configuratie", "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.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.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.javascriptSdk": "Use the JavaScript SDK",
"clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "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.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.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.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.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.sdkHelp": "Heb je een andere SDK nodig?",
"clients.connectWizard.sdkHelpLink": "Neem contact met ons op in het ondersteuningsforum", "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.step0Title": "Client instellen",
"clients.connectWizard.step1Title": "Kies verbindingsmethode", "clients.connectWizard.step1Title": "Kies verbindingsmethode",
"clients.connectWizard.step2Title": "Verbinden", "clients.connectWizard.step2Title": "Verbinden",
@ -387,6 +380,7 @@
"common.remember": "Onthoud mijn keuze", "common.remember": "Onthoud mijn keuze",
"common.rename": "Hernoemen", "common.rename": "Hernoemen",
"common.renameTag": "Hernoem Tag", "common.renameTag": "Hernoem Tag",
"common.repository": "Repository",
"common.requiredHint": "verplicht", "common.requiredHint": "verplicht",
"common.reset": "Reset", "common.reset": "Reset",
"common.restore": "Herstellen", "common.restore": "Herstellen",

14
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.started": "O reforço começou, pode levar vários minutos para ser concluído.",
"backups.startedLabel": "Começou", "backups.startedLabel": "Começou",
"backups.startFailed": "Falhou em começar o backup.", "backups.startFailed": "Falhou em começar o backup.",
"chat.answer": "Here is my answer:",
"chat.answers": "Answers", "chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
@ -194,16 +195,6 @@
"clients.connectWizard.cliStep3": "Adicione o nome da sua aplicação ao CLI config", "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.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.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.javascriptSdk": "Use the JavaScript SDK",
"clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "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.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.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.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.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.sdkHelp": "Precisa de outro SDK?",
"clients.connectWizard.sdkHelpLink": "Contacte-nos no Fórum de Apoio", "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.step0Title": "Cliente de configuração",
"clients.connectWizard.step1Title": "Escolha o método de ligação", "clients.connectWizard.step1Title": "Escolha o método de ligação",
"clients.connectWizard.step2Title": "Ligar", "clients.connectWizard.step2Title": "Ligar",
@ -387,6 +380,7 @@
"common.remember": "Não pergunte de novo.", "common.remember": "Não pergunte de novo.",
"common.rename": "Renomear", "common.rename": "Renomear",
"common.renameTag": "Renomear Etiqueta", "common.renameTag": "Renomear Etiqueta",
"common.repository": "Repository",
"common.requiredHint": "Necessário", "common.requiredHint": "Necessário",
"common.reset": "Reset", "common.reset": "Reset",
"common.restore": "Restaurar", "common.restore": "Restaurar",

14
backend/i18n/frontend_zh.json

@ -166,6 +166,7 @@
"backups.started": "备份已开始,可能需要几分钟才能完成。", "backups.started": "备份已开始,可能需要几分钟才能完成。",
"backups.startedLabel": "开始", "backups.startedLabel": "开始",
"backups.startFailed": "启动备份失败。", "backups.startFailed": "启动备份失败。",
"chat.answer": "Here is my answer:",
"chat.answers": "Answers", "chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
@ -194,16 +195,6 @@
"clients.connectWizard.cliStep3": "在 CLI 配置中添加你的应用名称", "clients.connectWizard.cliStep3": "在 CLI 配置中添加你的应用名称",
"clients.connectWizard.cliStep3Hint": "您可以在 CLI 中管理多个应用程序的配置并切换到一个应用程序。", "clients.connectWizard.cliStep3Hint": "您可以在 CLI 中管理多个应用程序的配置并切换到一个应用程序。",
"clients.connectWizard.cliStep4": "在 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.javascriptSdk": "Use the JavaScript SDK",
"clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "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.javascriptSdkHint": "Install the SDK and establish a connection to this app.",
@ -217,8 +208,10 @@
"clients.connectWizard.manuallyStep3": "将令牌作为 HTTP 标头添加到所有请求中", "clients.connectWizard.manuallyStep3": "将令牌作为 HTTP 标头添加到所有请求中",
"clients.connectWizard.manuallyTokenHint": "令牌通常会在 30 天后过期,但您可以请求多个令牌。", "clients.connectWizard.manuallyTokenHint": "令牌通常会在 30 天后过期,但您可以请求多个令牌。",
"clients.connectWizard.postManDocs": "从 [文档](https://docs.squidex.io/02-documentation/developer-guides/api-overview/postman) 中的 Postman 教程开始。", "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.sdkHelp": "你需要另一个 SDK?",
"clients.connectWizard.sdkHelpLink": "在支持论坛联系我们", "clients.connectWizard.sdkHelpLink": "在支持论坛联系我们",
"clients.connectWizard.sdkHint": "Install the SDK and establish a connection to this app.",
"clients.connectWizard.step0Title": "设置客户端", "clients.connectWizard.step0Title": "设置客户端",
"clients.connectWizard.step1Title": "选择连接方式", "clients.connectWizard.step1Title": "选择连接方式",
"clients.connectWizard.step2Title": "连接", "clients.connectWizard.step2Title": "连接",
@ -387,6 +380,7 @@
"common.remember": "不要再问了", "common.remember": "不要再问了",
"common.rename": "重命名", "common.rename": "重命名",
"common.renameTag": "Rename Tag", "common.renameTag": "Rename Tag",
"common.repository": "Repository",
"common.requiredHint": "必需的", "common.requiredHint": "必需的",
"common.reset": "重置", "common.reset": "重置",
"common.restore": "恢复", "common.restore": "恢复",

14
backend/i18n/source/frontend_en.json

@ -166,6 +166,7 @@
"backups.started": "Backup started, it can take several minutes to complete.", "backups.started": "Backup started, it can take several minutes to complete.",
"backups.startedLabel": "Started", "backups.startedLabel": "Started",
"backups.startFailed": "Failed to start backup.", "backups.startFailed": "Failed to start backup.",
"chat.answer": "Here is my answer:",
"chat.answers": "Answers", "chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.", "chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
@ -194,16 +195,6 @@
"clients.connectWizard.cliStep3": "Add your app name the CLI config", "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.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.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.javascriptSdk": "Use the JavaScript SDK",
"clients.connectWizard.javascriptSdkDocumentation": "Documentations for the JavaScript SDK is available: ", "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.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.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.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.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.sdkHelp": "You need another SDK?",
"clients.connectWizard.sdkHelpLink": "Contact us in the Support Forum", "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.step0Title": "Setup client",
"clients.connectWizard.step1Title": "Choose connection method", "clients.connectWizard.step1Title": "Choose connection method",
"clients.connectWizard.step2Title": "Connect", "clients.connectWizard.step2Title": "Connect",
@ -387,6 +380,7 @@
"common.remember": "Don't ask again", "common.remember": "Don't ask again",
"common.rename": "Rename", "common.rename": "Rename",
"common.renameTag": "Rename Tag", "common.renameTag": "Rename Tag",
"common.repository": "Repository",
"common.requiredHint": "required", "common.requiredHint": "required",
"common.reset": "Reset", "common.reset": "Reset",
"common.restore": "Restore", "common.restore": "Restore",

16
backend/i18n/source/frontend_fr.json

@ -183,22 +183,6 @@
"clients.connectWizard.cliStep3": "Ajoutez le nom de votre application à la configuration CLI", "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.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.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.manually": "Connectez-vous manuellement",
"clients.connectWizard.manuallyHint": "Obtenez des instructions pour établir une connexion avec Postman ou curl.", "clients.connectWizard.manuallyHint": "Obtenez des instructions pour établir une connexion avec Postman ou curl.",
"clients.connectWizard.manuallyStep1": "Obtenir un jeton en utilisant curl", "clients.connectWizard.manuallyStep1": "Obtenir un jeton en utilisant curl",

5
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.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.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.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.manually": "Connetti manualmente",
"clients.connectWizard.manuallyHint": "Leggi le istruzioni su come stabilire una connessione utilizzando Postman o curl.", "clients.connectWizard.manuallyHint": "Leggi le istruzioni su come stabilire una connessione utilizzando Postman o curl.",
"clients.connectWizard.manuallyStep1": "Ottenere un token usando curl", "clients.connectWizard.manuallyStep1": "Ottenere un token usando curl",

5
backend/i18n/source/frontend_nl.json

@ -169,11 +169,6 @@
"clients.connectWizard.cliStep3": "Voeg uw app-naam toe aan de CLI-configuratie", "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.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.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.manually": "Handmatig verbinden",
"clients.connectWizard.manuallyHint": "Krijg instructies om een ​​verbinding tot stand te brengen met Postman of curl.", "clients.connectWizard.manuallyHint": "Krijg instructies om een ​​verbinding tot stand te brengen met Postman of curl.",
"clients.connectWizard.manuallyStep1": "Verkrijg een token met curl", "clients.connectWizard.manuallyStep1": "Verkrijg een token met curl",

5
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.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.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.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.manually": "Conecte-se manualmente",
"clients.connectWizard.manuallyHint": "Obtenha instruções sobre como estabelecer uma ligação com o Carteiro ou o caracol.", "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", "clients.connectWizard.manuallyStep1": "Obter um símbolo usando caracóis",

5
backend/i18n/source/frontend_zh.json

@ -157,11 +157,6 @@
"clients.connectWizard.cliStep3": "在 CLI 配置中添加你的应用名称", "clients.connectWizard.cliStep3": "在 CLI 配置中添加你的应用名称",
"clients.connectWizard.cliStep3Hint": "您可以在 CLI 中管理多个应用程序的配置并切换到一个应用程序。", "clients.connectWizard.cliStep3Hint": "您可以在 CLI 中管理多个应用程序的配置并切换到一个应用程序。",
"clients.connectWizard.cliStep4": "在 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.manually": "手动连接",
"clients.connectWizard.manuallyHint": "获取如何与 Postman 或 curl 建立连接的说明。", "clients.connectWizard.manuallyHint": "获取如何与 Postman 或 curl 建立连接的说明。",
"clients.connectWizard.manuallyStep1": "使用 curl 获取令牌", "clients.connectWizard.manuallyStep1": "使用 curl 获取令牌",

2
frontend/src/app/app.component.html

@ -1,4 +1,4 @@
<main> <main sqxCopyGlobal>
<sqx-root-view> <sqx-root-view>
<router-outlet (activate)="isLoaded = true"> <router-outlet (activate)="isLoaded = true">
<div class="loading" *ngIf="!isLoaded"> <div class="loading" *ngIf="!isLoaded">

104
frontend/src/app/features/content/shared/forms/chat-dialog.component.html

@ -1,17 +1,84 @@
<sqx-modal-dialog size="lg" (close)="close.emit()"> <sqx-modal-dialog size="lg" (close)="close.emit()" fullHeight="true">
<ng-container title> <ng-container title>
{{ 'chat.title' | sqxTranslate }} {{ 'chat.title' | sqxTranslate }}
</ng-container> </ng-container>
<ng-container content> <ng-container content>
<sqx-form-alert marginBottom="4"> <div class="item">
<span [sqxMarkdown]="'chat.description' | sqxTranslate" inline="true"></span> <div class="row">
</sqx-form-alert> <div class="col-auto">
<div class="squid squid-sm d-flex align-items-center justify-content-center">
<img src="./images/squid.svg">
</div>
</div>
<div class="col">
<div class="bubble bubble-right">
<span [sqxMarkdown]="'chat.description' | sqxTranslate" inline="false"></span>
</div>
</div>
</div>
</div>
<div class="item" *ngFor="let item of snapshot.chatTalk">
<div class="row mt-3" *ngIf="item.isUser">
<div class="col">
<div class="bubble bubble-left">
{{item.prompt}}
</div>
</div>
<div class="col-auto">
<img class="user-picture" title="{{user.displayName}}" [src]="user.id | sqxUserIdPicture" />
</div>
</div>
<div class="row mt-3" *ngIf="!item.isUser">
<div class="col-auto">
<div class="squid squid-sm d-flex align-items-center justify-content-center">
<img src="./images/squid.svg">
</div>
</div>
<div class="col">
<div class="bubble bubble-right">
<div class="mb-2">
{{ 'chat.answer' | sqxTranslate}}
</div>
<textarea class="form-control" readonly [ngModel]="item.prompt"></textarea>
<div class="mt-2">
<button type="button" class="btn btn-primary" (click)="select.emit(item.prompt)">
{{ 'chat.use' | sqxTranslate }}
</button>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-3" *ngIf="snapshot.isRunning">
<div class="col-auto">
<div class="squid squid-sm d-flex align-items-center justify-content-center">
<img src="./images/squid.svg">
</div>
</div>
<div class="col">
<div class="bubble bubble-right">
<svg height="40" width="40" class="loader">
<circle class="dot" cx="10" cy="20" r="3" />
<circle class="dot" cx="20" cy="20" r="3" />
<circle class="dot" cx="30" cy="20" r="3" />
</svg>
</div>
</div>
</div>
</ng-container>
<ng-container footer>
<form (ngSubmit)="ask()"> <form (ngSubmit)="ask()">
<div class="row row-cols-0 g-2"> <div class="row row-cols-0 g-2">
<div class="col"> <div class="col">
<input class="form-control" placeholder="{{ 'chat.prompt' | sqxTranslate }}" <input class="form-control" #input
placeholder="{{ 'chat.prompt' | sqxTranslate }}"
sqxFocusOnInit sqxFocusOnInit
(ngModelChange)="setQuestion($event)" (ngModelChange)="setQuestion($event)"
[ngModel]="snapshot.chatQuestion" [ngModel]="snapshot.chatQuestion"
@ -25,32 +92,5 @@
</div> </div>
</div> </div>
</form> </form>
<ng-container *ngIf="!snapshot.isRunning; else loading">
<ng-container *ngIf="snapshot.chatAnswers">
<h4 class="mt-4">{{ 'chat.answers' | sqxTranslate }}</h4>
<div *ngIf="snapshot.chatAnswers?.length === 0">
<small class="text-muted">{{ 'chat.answersEmpty' | sqxTranslate }}</small>
</div>
<div class="row g-2 answer" *ngFor="let answer of (snapshot.chatAnswers || [])">
<div class="col">
<textarea class="form-control" readonly [ngModel]="answer"></textarea>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary" (click)="select.emit(answer)">
{{ 'chat.use' | sqxTranslate }}
</button>
</div>
</div>
</ng-container>
</ng-container>
<ng-template #loading>
<div class="mt-4">
<sqx-loader></sqx-loader>
</div>
</ng-template>
</ng-container> </ng-container>
</sqx-modal-dialog> </sqx-modal-dialog>

60
frontend/src/app/features/content/shared/forms/chat-dialog.component.scss

@ -1,6 +1,66 @@
@import 'mixins'; @import 'mixins';
@import 'vars'; @import 'vars';
:host ::ng-deep {
.modal-body {
background-color: $color-background;
}
}
form {
width: 100%;
}
textarea { textarea {
height: 300px; 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;
} }

47
frontend/src/app/features/content/shared/forms/chat-dialog.component.ts

@ -5,8 +5,8 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { Component, EventEmitter, Output } from '@angular/core'; import { Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core';
import { AppsState, StatefulComponent, TranslationsService } from '@app/shared'; import { AppsState, AuthService, StatefulComponent, TranslationsService } from '@app/shared';
interface State { interface State {
// True, when running // True, when running
@ -16,7 +16,7 @@ interface State {
chatQuestion: string; chatQuestion: string;
// The answers. // The answers.
chatAnswers?: ReadonlyArray<string>; chatTalk: ReadonlyArray<{ prompt: string; isUser?: boolean }>;
} }
@Component({ @Component({
@ -31,14 +31,20 @@ export class ChatDialogComponent extends StatefulComponent<State> {
@Output() @Output()
public select = new EventEmitter<string>(); public select = new EventEmitter<string>();
@ViewChild('input', { static: false })
public input!: ElementRef<HTMLInputElement>;
public user = this.authService.user!;
constructor( constructor(
private readonly appsState: AppsState, private readonly appsState: AppsState,
private readonly authService: AuthService,
private readonly translator: TranslationsService, private readonly translator: TranslationsService,
) { ) {
super({ super({
isRunning: false, isRunning: false,
chatQuestion: '', chatQuestion: '',
chatAnswers: undefined, chatTalk: [],
}); });
} }
@ -47,15 +53,40 @@ export class ChatDialogComponent extends StatefulComponent<State> {
} }
public ask() { 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({ .subscribe({
next: chatAnswers => { 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: () => { error: () => {
this.next({ chatAnswers: [], isRunning: false }); this.next({ isRunning: false });
}, },
complete: () => { complete: () => {
this.next({ isRunning: false }); this.next({ isRunning: false });

2
frontend/src/app/features/content/shared/forms/field-editor.component.ts

@ -57,7 +57,7 @@ export class FieldEditorComponent {
public isEmpty?: Observable<boolean>; public isEmpty?: Observable<boolean>;
public isExpanded = false; public isExpanded = false;
public chatDialog = new DialogModel(); public chatDialog = new DialogModel(true);
public get field() { public get field() {
return this.formModel.field; return this.formModel.field;

145
frontend/src/app/features/settings/pages/clients/client-connect-form.component.html

@ -9,7 +9,7 @@
<li class="breadcrumb-item done"> <li class="breadcrumb-item done">
<i class="icon-checkmark"></i> {{ 'clients.connectWizard.step0Title' | sqxTranslate }} <i class="icon-checkmark"></i> {{ 'clients.connectWizard.step0Title' | sqxTranslate }}
</li> </li>
<ng-container *ngIf="isStart; else noStart"> <ng-container *ngIf="step === 'Start'; else noStart">
<li class="breadcrumb-item active"> <li class="breadcrumb-item active">
<span> <span>
<i class="icon-checkmark"></i> {{ 'clients.connectWizard.step1Title' | sqxTranslate }} <i class="icon-checkmark"></i> {{ 'clients.connectWizard.step1Title' | sqxTranslate }}
@ -23,7 +23,7 @@
</a> </a>
</li> </li>
</ng-template> </ng-template>
<li class="breadcrumb-item" [class.active]="!isStart"> <li class="breadcrumb-item" [class.active]="step !== 'Start'">
<i class="icon-checkmark"></i> {{ 'clients.connectWizard.step2Title' | sqxTranslate }} <i class="icon-checkmark"></i> {{ 'clients.connectWizard.step2Title' | sqxTranslate }}
</li> </li>
</ol> </ol>
@ -54,18 +54,10 @@
<i class="icon-angle-right"></i> <i class="icon-angle-right"></i>
</div> </div>
<div class="option" (click)="go('SDK_Dotnet')"> <div class="option" (click)="go('SDK')">
<h5>{{ 'clients.connectWizard.dotnetSdk' | sqxTranslate }}</h5> <h5>{{ 'clients.connectWizard.sdk' | sqxTranslate }}</h5>
<sqx-form-hint>{{ 'clients.connectWizard.dotnetSdkHint' | sqxTranslate }}</sqx-form-hint> <sqx-form-hint>{{ 'clients.connectWizard.sdkHint' | sqxTranslate }}</sqx-form-hint>
<i class="icon-angle-right"></i>
</div>
<div class="option" (click)="go('SDK_Javascript')">
<h5>{{ 'clients.connectWizard.javascriptSdk' | sqxTranslate }}</h5>
<sqx-form-hint>{{ 'clients.connectWizard.javascriptSdkHint' | sqxTranslate }}</sqx-form-hint>
<i class="icon-angle-right"></i> <i class="icon-angle-right"></i>
</div> </div>
@ -144,132 +136,35 @@
</p> </p>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'SDK_Dotnet'"> <ng-container *ngSwitchCase="'SDK'">
<div class="section step"> <div *ngIf="sdks | async; let sdks">
<sqx-form-hint> <div class="sdk-header"*ngFor="let availableSDK of sdks | keyvalue" [class.active]="sdk === availableSDK.value" (click)="select(availableSDK.value)">
{{ 'clients.connectWizard.dotnetSdkDocumentation' | sqxTranslate }} <a href="https://docs.squidex.io/02-documentation/software-development-kits/.net-standard" sqxExternalLink>{{ 'common.documentation' | sqxTranslate }}</a> <div class="logo d-flex align-items-center justify-content-center" [innerHTML]="availableSDK.value.logo | sqxSafeHtml"></div>
</sqx-form-hint> {{availableSDK.value.name}}
</div> </div>
<div class="section step">
<h5><span class="badge rounded-pill bg-dark">1</span> {{ 'clients.connectWizard.dotnetSdkStep1' | sqxTranslate }}</h5>
<div [innerHTML]="'clients.connectWizard.dotnetSdkStep1Download' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div>
<p>
<sqx-code>dotnet add package Squidex.ClientLibrary</sqx-code>
</p>
</div>
<div class="section step">
<h5><span class="badge rounded-pill bg-dark">2</span> {{ 'clients.connectWizard.dotnetSdkStep2' | sqxTranslate }}</h5>
<p>
<sqx-code>
<div ngPreserveWhitespaces>using Squidex.ClientLibrary;</div>
<div ngPreserveWhitespaces>&nbsp;</div>
<div ngPreserveWhitespaces>var clientManager = new SquidexClientManager(new SquidexOptions</div>
<div ngPreserveWhitespaces>{{'{'}}</div>
<div ngPreserveWhitespaces> AppName = "{{appName}}",</div>
<div ngPreserveWhitespaces> ClientId = "{{appName}}:{{client.id}}",</div>
<div ngPreserveWhitespaces> ClientSecret = "{{client.secret}}",</div>
<div ngPreserveWhitespaces> Url = "{{apiUrl.value}}"</div>
<div ngPreserveWhitespaces>});</div>
</sqx-code>
</p>
</div>
<div class="section step">
<h5><span class="badge rounded-pill bg-dark">2</span> {{ 'clients.connectWizard.dotnetSdkStep2_15' | sqxTranslate }}</h5>
<p>
<sqx-code>
<div ngPreserveWhitespaces>using Squidex.ClientLibrary;</div>
<div ngPreserveWhitespaces>&nbsp;</div>
<div ngPreserveWhitespaces>var client = new SquidexClient(new SquidexOptions</div>
<div ngPreserveWhitespaces>{{'{'}}</div>
<div ngPreserveWhitespaces> AppName = "{{appName}}",</div>
<div ngPreserveWhitespaces> ClientId = "{{appName}}:{{client.id}},</div>
<div ngPreserveWhitespaces> ClientSecret = "{{client.secret}}",</div>
<div ngPreserveWhitespaces> Url = "{{apiUrl.value}}"</div>
<div ngPreserveWhitespaces>});</div>
</sqx-code>
</p>
</div>
<div class="section step">
<h5><span class="badge rounded-pill bg-dark">3</span> {{ 'clients.connectWizard.dotnetSdkStep3' | sqxTranslate }}</h5>
<div [innerHTML]="'clients.connectWizard.dotnetSdkStep3Download' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div>
<p>
<sqx-code>dotnet add package Squidex.ClientLibrary.ServiceExtensions</sqx-code>
</p>
</div> </div>
<div class="section step"> <div class="section markdown" *ngIf="sdk">
<h5><span class="badge rounded-pill bg-dark">4</span> {{ 'clients.connectWizard.dotnetSdkStep4' | sqxTranslate }}</h5> <div>
<a [attr.href]="sdk.documentation" sqxExternalLink>{{ 'common.documentation' | sqxTranslate }}</a>
<span> &middot; </span>
<a [attr.href]="sdk.repository" sqxExternalLink>{{ 'common.repository' | sqxTranslate }}</a>
</div>
<p> <span [sqxMarkdown]="sdk.instructions" inline="false" trusted="true"></span>
<sqx-code>
<div ngPreserveWhitespaces>using Microsoft.Extensions.DependencyInjection;</div>
<div ngPreserveWhitespaces>&nbsp;</div>
<div ngPreserveWhitespaces>services.AddSquidex(options =></div>
<div ngPreserveWhitespaces>{{'{'}}</div>
<div ngPreserveWhitespaces> options.AppName = "{{appName}}";</div>
<div ngPreserveWhitespaces> options.ClientId = "{{appName}}:{{client.id}}";</div>
<div ngPreserveWhitespaces> options.ClientSecret = "{{client.secret}}";</div>
<div ngPreserveWhitespaces> options.Url = "{{apiUrl.value}}";</div>
<div ngPreserveWhitespaces>});</div>
</sqx-code>
</p>
</div> </div>
<div class="section step"> <div class="section" *ngIf="sdk">
<sqx-form-hint> <sqx-form-hint>
{{ 'clients.connectWizard.sdkHelp' | sqxTranslate }} <a href="https://support.squidex.io" sqxExternalLink>{{ 'clients.connectWizard.sdkHelpLink' | sqxTranslate }}</a> {{ 'clients.connectWizard.sdkHelp' | sqxTranslate }} <a href="https://support.squidex.io" sqxExternalLink>{{ 'clients.connectWizard.sdkHelpLink' | sqxTranslate }}</a>
</sqx-form-hint> </sqx-form-hint>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'SDK_Javascript'">
<div class="section step">
<sqx-form-hint>
{{ 'clients.connectWizard.javascriptSdkDocumentation' | sqxTranslate }} <a href="https://docs.squidex.io/02-documentation/software-development-kits/javascript" sqxExternalLink>{{ 'common.documentation' | sqxTranslate }}</a>
</sqx-form-hint>
</div>
<div class="section step">
<h5><span class="badge rounded-pill bg-dark">1</span> {{ 'clients.connectWizard.javascriptSdkStep1' | sqxTranslate }}</h5>
<div [innerHTML]="'clients.connectWizard.javascriptSdkStep1Download' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div>
<p>
<sqx-code>npm i @squidex/squidex --save</sqx-code>
</p>
</div>
<div class="section step">
<h5><span class="badge rounded-pill bg-dark">2</span> {{ 'clients.connectWizard.javascriptSdkStep2' | sqxTranslate }}</h5>
<p>
<sqx-code>
<div ngPreserveWhitespaces>import {{'{'}} SquidexClient } from "@squidex/squidex";</div>
<div ngPreserveWhitespaces>&nbsp;</div>
<div ngPreserveWhitespaces>const client = new SquidexClient({{'{'}}</div>
<div ngPreserveWhitespaces> appName: "{{appName}}",</div>
<div ngPreserveWhitespaces> clientId: "{{appName}}:{{client.id}}",</div>
<div ngPreserveWhitespaces> clientSecret: "{{client.secret}}",</div>
<div ngPreserveWhitespaces> environment: "{{apiUrl.value}}"</div>
<div ngPreserveWhitespaces>});</div>
</sqx-code>
</p>
</div>
</ng-container>
</ng-container> </ng-container>
</ng-container> </ng-container>
<ng-container footer> <ng-container footer>
<button class="btn btn-text-secondary" [disabled]="isStart" (click)="go('Start')"> <button class="btn btn-text-secondary" [disabled]="step === 'Start'" (click)="go('Start')">
{{ 'common.back' | sqxTranslate }} {{ 'common.back' | sqxTranslate }}
</button> </button>
</ng-container> </ng-container>

50
frontend/src/app/features/settings/pages/clients/client-connect-form.component.scss

@ -1,6 +1,26 @@
@import 'mixins'; @import 'mixins';
@import 'vars'; @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 { .badge {
@include circle(1.3rem); @include circle(1.3rem);
font-size: $font-smallest; 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 { .option {
background: none; background: none;
border: 1px solid $color-border; border: 1px solid $color-border;
@ -43,10 +87,4 @@
font-size: $font-smallest; font-size: $font-smallest;
font-weight: normal; font-weight: normal;
} }
}
sqx-code {
pre {
white-space: pre;
}
} }

19
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 { 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({ @Component({
selector: 'sqx-client-connect-form', selector: 'sqx-client-connect-form',
@ -20,21 +20,21 @@ export class ClientConnectFormComponent implements OnInit {
@Input({ required: true }) @Input({ required: true })
public client!: ClientDto; public client!: ClientDto;
public sdks = this.helpService.getSDKs();
public sdk?: SDKEntry;
public appName!: string; public appName!: string;
public appToken?: AccessTokenDto; public appToken?: AccessTokenDto;
public step = 'Start'; public step = 'Start';
public get isStart() {
return this.step === 'Start';
}
constructor( constructor(
public readonly appsState: AppsState, public readonly appsState: AppsState,
public readonly apiUrl: ApiUrlConfig, public readonly apiUrl: ApiUrlConfig,
private readonly changeDetector: ChangeDetectorRef, private readonly changeDetector: ChangeDetectorRef,
private readonly clientsService: ClientsService, private readonly clientsService: ClientsService,
private readonly dialogs: DialogService, private readonly dialogs: DialogService,
private readonly helpService: HelpService,
private readonly messageBus: MessageBus, private readonly messageBus: MessageBus,
) { ) {
} }
@ -57,6 +57,15 @@ export class ClientConnectFormComponent implements OnInit {
this.messageBus.emit(new ClientTourStated()); this.messageBus.emit(new ClientTourStated());
} }
public select(sdk: SDKEntry) {
sdk.instructions = sdk.instructions.replace(/<APP_NAME>/g, this.appName);
sdk.instructions = sdk.instructions.replace(/<CLIENT_ID>/g, `${this.appName}:${this.client.id}`);
sdk.instructions = sdk.instructions.replace(/<CLIENT_SECRET>/g, this.client.secret);
sdk.instructions = sdk.instructions.replace(/<URL>/g, this.apiUrl.value);
this.sdk = sdk;
}
public go(step: string) { public go(step: string) {
this.step = step; this.step = step;
} }

2
frontend/src/app/features/settings/pages/clients/client.component.ts

@ -23,7 +23,7 @@ export class ClientComponent {
public apiCallsLimit = 0; public apiCallsLimit = 0;
public connectDialog = new DialogModel(); public connectDialog = new DialogModel(false);
constructor( constructor(
public readonly appsState: AppsState, public readonly appsState: AppsState,

6
frontend/src/app/framework/angular/code.component.html

@ -1,7 +1,7 @@
<div class="copy-container"> <div class="code-container">
<button type="button" class="code-copy" [sqxCopy]="codeBlock"> <button type="button" class="code-copy" [attr.copy]="id">
<i class="icon-copy"></i> <i class="icon-copy"></i>
</button> </button>
<pre class="code" #codeBlock><ng-content></ng-content></pre> <pre class="code" [attr.id]="id"><ng-content></ng-content></pre>
</div> </div>

34
frontend/src/app/framework/angular/code.component.scss

@ -1,34 +1,2 @@
@import 'mixins'; @import 'mixins';
@import 'vars'; @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%);
}
}

5
frontend/src/app/framework/angular/code.component.ts

@ -6,6 +6,7 @@
*/ */
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { MathHelper } from '../internal';
@Component({ @Component({
selector: 'sqx-code', selector: 'sqx-code',
@ -13,4 +14,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
templateUrl: './code.component.html', templateUrl: './code.component.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class CodeComponent {} export class CodeComponent {
public readonly id = MathHelper.guid();
}

91
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;
}
}
}

5
frontend/src/app/framework/angular/markdown.directive.ts

@ -15,6 +15,9 @@ export class MarkdownDirective {
@Input('sqxMarkdown') @Input('sqxMarkdown')
public markdown!: string; public markdown!: string;
@Input({ transform: booleanAttribute })
public trusted = false;
@Input({ transform: booleanAttribute }) @Input({ transform: booleanAttribute })
public inline = true; public inline = true;
@ -43,7 +46,7 @@ export class MarkdownDirective {
} else if (this.optional && !hasExclamation) { } else if (this.optional && !hasExclamation) {
html = markdown; html = markdown;
} else if (this.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; const hasHtml = html.indexOf('<') >= 0 || html.indexOf('&') >= 0;

1
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-messages.component';
export * from './angular/forms/control-errors.component'; export * from './angular/forms/control-errors.component';
export * from './angular/forms/copy.directive'; export * from './angular/forms/copy.directive';
export * from './angular/forms/copy-global.directive';
export * from './angular/forms/editable-title.component'; export * from './angular/forms/editable-title.component';
export * from './angular/forms/editors/autocomplete.component'; export * from './angular/forms/editors/autocomplete.component';
export * from './angular/forms/editors/checkbox-group.component'; export * from './angular/forms/editors/checkbox-group.component';

4
frontend/src/app/framework/module.ts

@ -12,7 +12,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { ColorPickerModule } from 'ngx-color-picker'; import { ColorPickerModule } from 'ngx-color-picker';
import { TourService as BaseTourService } from 'ngx-ui-tour-core'; 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({ @NgModule({
imports: [ imports: [
@ -34,6 +34,7 @@ import { AnalyticsService, AutocompleteComponent, AvatarComponent, CachingInterc
ControlErrorsComponent, ControlErrorsComponent,
ControlErrorsMessagesComponent, ControlErrorsMessagesComponent,
CopyDirective, CopyDirective,
CopyGlobalDirective,
DarkenPipe, DarkenPipe,
DatePipe, DatePipe,
DateTimeEditorComponent, DateTimeEditorComponent,
@ -124,6 +125,7 @@ import { AnalyticsService, AutocompleteComponent, AvatarComponent, CachingInterc
ConfirmClickDirective, ConfirmClickDirective,
ControlErrorsComponent, ControlErrorsComponent,
CopyDirective, CopyDirective,
CopyGlobalDirective,
DarkenPipe, DarkenPipe,
DatePipe, DatePipe,
DateTimeEditorComponent, DateTimeEditorComponent,

23
frontend/src/app/framework/utils/markdown.ts

@ -6,6 +6,7 @@
*/ */
import { marked } from 'marked'; import { marked } from 'marked';
import { MathHelper } from './math-helper';
function renderLink(href: string, _: string, text: string) { function renderLink(href: string, _: string, text: string) {
if (href && href.startsWith('mailto')) { 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 `
<div class="code-container">
<button type="button" class="code-copy" copy="${id}">
<i class="icon-copy"></i>
</button>
<pre class="code" id="${id}">${code}</pre>
</div>
`;
}
function renderInlineParagraph(text: string) { function renderInlineParagraph(text: string) {
return text; return text;
} }
@ -24,14 +39,18 @@ const RENDERER_INLINE = new marked.Renderer();
RENDERER_INLINE.paragraph = renderInlineParagraph; RENDERER_INLINE.paragraph = renderInlineParagraph;
RENDERER_INLINE.link = renderLink; RENDERER_INLINE.link = renderLink;
RENDERER_INLINE.code = renderCode;
RENDERER_DEFAULT.link = renderLink; 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) { if (!input) {
return ''; return '';
} }
input = escapeHTML(input); if (!trusted) {
input = escapeHTML(input);
}
if (inline) { if (inline) {
return marked(input, { renderer: RENDERER_INLINE, mangle: false, headerIds: false }); return marked(input, { renderer: RENDERER_INLINE, mangle: false, headerIds: false });

42
frontend/src/app/shared/services/help.service.spec.ts

@ -9,7 +9,7 @@
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing'; import { inject, TestBed } from '@angular/core/testing';
import { HelpService } from '@app/shared/internal'; import { HelpService, SDKEntry } from '@app/shared/internal';
describe('HelpService', () => { describe('HelpService', () => {
beforeEach(() => { beforeEach(() => {
@ -62,4 +62,44 @@ describe('HelpService', () => {
expect(helpSections!).toEqual(''); expect(helpSections!).toEqual('');
})); }));
it('should make get request to get sdks',
inject([HelpService, HttpTestingController], (helpService: HelpService, httpMock: HttpTestingController) => {
let sdks: Record<string, SDKEntry>;
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<string, SDKEntry>;
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(<any>{});
expect(sdks!).toEqual({});
}));
}); });

24
frontend/src/app/shared/services/help.service.ts

@ -10,6 +10,23 @@ import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators'; 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() @Injectable()
export class HelpService { export class HelpService {
constructor( constructor(
@ -23,4 +40,11 @@ export class HelpService {
return this.http.get(url, { responseType: 'text' }).pipe( return this.http.get(url, { responseType: 'text' }).pipe(
catchError(() => of(''))); catchError(() => of('')));
} }
public getSDKs(): Observable<Record<string, SDKEntry>> {
const url = 'https://raw.githubusercontent.com/Squidex/sdk-fern/main/sdks.json';
return this.http.get<Record<string, SDKEntry>>(url).pipe(
catchError(() => of({})));
}
} }

38
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 // Profile picture in circle
// //
@ -187,6 +221,10 @@ hr {
img { img {
max-height: 70%; max-height: 70%;
} }
&-sm {
@include circle(32px);
}
} }
.ngx-ui-tour_backdrop { .ngx-ui-tour_backdrop {

Loading…
Cancel
Save