diff --git a/backend/i18n/frontend_en.json b/backend/i18n/frontend_en.json index 45577deae..73118fb70 100644 --- a/backend/i18n/frontend_en.json +++ b/backend/i18n/frontend_en.json @@ -12,11 +12,11 @@ "apps.appNameWarning": "The app name cannot be changed later.", "apps.appsButtonCreate": "Apps Overview", "apps.appsButtonFallbackTitle": "Apps Overview", - "apps.archieve": "Archive App", - "apps.archieveConfirmText": "Do you really want to archive this App?", - "apps.archieveConfirmTitle": "Archive App", - "apps.archieveWarning": "Once you archive an app, there is no going back. Please be certain.", + "apps.archive": "Archive App", + "apps.archiveConfirmText": "Do you really want to archive this app?", + "apps.archiveConfirmTitle": "Archive App", "apps.archiveFailed": "Failed to archive app. Please reload.", + "apps.archiveWarning": "Once you archive an app, there is no going back. Please be certain.", "apps.create": "Create App", "apps.createBlankApp": "New App", "apps.createBlankAppDescription": "Create a new blank app without content and schemas.", diff --git a/backend/i18n/frontend_it.json b/backend/i18n/frontend_it.json index a979fda99..f01614d4b 100644 --- a/backend/i18n/frontend_it.json +++ b/backend/i18n/frontend_it.json @@ -12,11 +12,11 @@ "apps.appNameWarning": "Il nome della app non potrà essere cambiato in un secondo momento.", "apps.appsButtonCreate": "Nuova App", "apps.appsButtonFallbackTitle": "Lista App", - "apps.archieve": "Archivia l'App", - "apps.archieveConfirmText": "Rimuovi il pattern", - "apps.archieveConfirmTitle": "Sei sicuro di voler archiviare questa app?", - "apps.archieveWarning": "Una volta archiviata una App, non è possibile tornare indietro. Sii certo.", + "apps.archive": "Archivia l'App", + "apps.archiveConfirmText": "Rimuovi il pattern", + "apps.archiveConfirmTitle": "Sei sicuro di voler archiviare questa app?", "apps.archiveFailed": "Non è stato possibile archiviare l'app. Per favore ricarica.", + "apps.archiveWarning": "Una volta archiviata una App, non è possibile tornare indietro. Sii certo.", "apps.create": "Crea un'App", "apps.createBlankApp": "Nuova App.", "apps.createBlankAppDescription": "Crea una app vuota senza contenuti o schema.", diff --git a/backend/i18n/frontend_nl.json b/backend/i18n/frontend_nl.json index 5f966d10a..a08982012 100644 --- a/backend/i18n/frontend_nl.json +++ b/backend/i18n/frontend_nl.json @@ -12,11 +12,11 @@ "apps.appNameWarning": "De app-naam kan later niet worden gewijzigd.", "apps.appsButtonCreate": "Apps-overzicht", "apps.appsButtonFallbackTitle": "Apps-overzicht", - "apps.archieve": "App archiveren", - "apps.archieveConfirmText": "Patroon verwijderen", - "apps.archieveConfirmTitle": "Wil je deze app echt archiveren?", - "apps.archieveWarning": "Zodra je een app archiveert, is er geen weg meer terug. Wees alsjeblieft zeker.", + "apps.archive": "App archiveren", + "apps.archiveConfirmText": "Patroon verwijderen", + "apps.archiveConfirmTitle": "Wil je deze app echt archiveren?", "apps.archiveFailed": "Kan app niet archiveren. Laad opnieuw.", + "apps.archiveWarning": "Zodra je een app archiveert, is er geen weg meer terug. Wees alsjeblieft zeker.", "apps.create": "App maken", "apps.createBlankApp": "Nieuwe app.", "apps.createBlankAppDescription": "Maak een nieuwe lege app zonder inhoud en schema's.", diff --git a/backend/i18n/source/backend_en.json b/backend/i18n/source/backend_en.json index d81ad1a30..4b4c6a32f 100644 --- a/backend/i18n/source/backend_en.json +++ b/backend/i18n/source/backend_en.json @@ -7,7 +7,6 @@ "annotations_Required": "The field {name|lower} is required.", "annotations_StringLength": "The field {name|lower} must be a string with a maximum length of {max}.", "annotations_StringLengthMinimum": "The field {name|lower} must be a string with a minimum length of {min} and a maximum length of {max}.", - "apps.alreadyArchieved": "App has already been archived.", "apps.clients.idAlreadyExists": "A client with the same id already exists.", "apps.contributors.cannotChangeYourself": "You cannot change your own role.", "apps.contributors.maxReached": "You have reached the maximum number of contributors for your plan.", @@ -28,8 +27,6 @@ "apps.roles.nameAlreadyExists": "A role with the same name already exists.", "apps.roles.usedRoleByClientsNotRemovable": "Cannot remove a role when a client is assigned.", "apps.roles.usedRoleByContributorsNotRemovable": "Cannot remove a role when a contributor is assigned.", - "assets.assetAlreadyDeleted": "Asset has already been deleted", - "assets.assetFolderAlreadyDeleted": "Asset folder has already been deleted", "assets.folderNotFound": "Asset folder does not exist.", "assets.folderRecursion": "Cannot add folder to its own child.", "assets.maxSizeReached": "You have reached your max asset size.", @@ -126,7 +123,6 @@ "contents.bulkInsertQueryNotUnique": "More than one content matches to the query.", "contents.draftNotCreateForUnpublished": "You can only create a new version when the content is published.", "contents.draftToDeleteNotFound": "There is nothing to delete.", - "contents.invalidArrayOfIds": "Invalid json type, expected array of guid strings.", "contents.invalidArrayOfObjects": "Invalid json type, expected array of objects.", "contents.invalidArrayOfStrings": "Invalid json type, expected array of strings.", "contents.invalidBoolean": "Invalid json type, expected boolean.", @@ -249,9 +245,7 @@ "history.schemas.updated": "updated schema {[Name]}.", "history.statusChanged": "changed status of {[Schema]} content to {[Status]}.", "login.githubPrivateEmail": "Your email address is set to private in Github. Please set it to public to use Github login.", - "rules.alreadyDeleted": "Rule has already been deleted.", "rules.ruleAlreadyRunning": "Another rule is already running.", - "schemas.alreadyDeleted": "Schema has already been deleted.", "schemas.dateTimeCalculatedDefaultAndDefaultError": "Calculated default value and default value cannot be used together.", "schemas.duplicateFieldName": "Field '{field}' has been added twice.", "schemas.fieldCannotBeUIField": "Field cannot be an UI field.", diff --git a/backend/i18n/source/backend_it.json b/backend/i18n/source/backend_it.json index 5c7236d20..c8ac6806c 100644 --- a/backend/i18n/source/backend_it.json +++ b/backend/i18n/source/backend_it.json @@ -7,7 +7,6 @@ "annotations_Required": "Il campo è {name|lower} obbligatorio.", "annotations_StringLength": "The field {name|lower} must be a string with a maximum length of {max}.", "annotations_StringLengthMinimum": "The field {name|lower} must be a string with a minimum length of {min} and a maximum length of {max}.", - "apps.alreadyArchieved": "La App è stata già archiviata.", "apps.clients.idAlreadyExists": "Un client con lo stesso id esiste già.", "apps.contributors.cannotChangeYourself": "Non puoi cambiare il tuo ruolo.", "apps.contributors.maxReached": "Hai raggiunto il numero massimo di contributori previsto per il tuo piano.", @@ -28,8 +27,6 @@ "apps.roles.nameAlreadyExists": "Esiste già un ruolo con lo stesso nome.", "apps.roles.usedRoleByClientsNotRemovable": "Non è possibile rimuovere un ruolo quando è assegnato ad un ruolo.", "apps.roles.usedRoleByContributorsNotRemovable": "Non è possibile rimuovere un ruolo quando questo è assegnato ad un collaboratore.", - "assets.assetAlreadyDeleted": "La risorsa è stata già eliminata", - "assets.assetFolderAlreadyDeleted": "La cartella delle risorse è stata già eliminata", "assets.folderNotFound": "La cartella delle risorse non esiste.", "assets.folderRecursion": "Non è possibile aggiungere una cartella al proprio figlio.", "assets.maxSizeReached": "Hai raggiunto la dimensione massima consentito per le risorse.", @@ -125,7 +122,6 @@ "contents.bulkInsertQueryNotUnique": "Ci sono più contenuti che corrispondono alla query.", "contents.draftNotCreateForUnpublished": "Puoi creare versioni del contenuto solo se questo è pubblicato.", "contents.draftToDeleteNotFound": "Non c'è niente da eliminare.", - "contents.invalidArrayOfIds": "Errore nel json, atteso un array di string guid.", "contents.invalidArrayOfObjects": "Errore nel json, attesp un array di objects.", "contents.invalidArrayOfStrings": "Errore nel json, atteso un array di string.", "contents.invalidBoolean": "Errore nel json, atteso un boolean.", @@ -245,9 +241,7 @@ "history.schemas.updated": "ha aggiornato lo schema {[Name]}.", "history.statusChanged": "ha cambiato lo stato del contenuto {[Schema]} in {[Status]}.", "login.githubPrivateEmail": "Il tuo indirizzo email è impostato su privato in Github. Impostalo come pubblico per poter utilizzare il login Github.", - "rules.alreadyDeleted": "La regola è stata già cancellata.", "rules.ruleAlreadyRunning": "E' in esecuzione un'altra regola.", - "schemas.alreadyDeleted": "Lo schema è stato già cancellato.", "schemas.dateTimeCalculatedDefaultAndDefaultError": "Il valore predefinito calcolato e il valore predefinito non possono essere utilizzati insieme.", "schemas.duplicateFieldName": "Il campo '{field}' è stato aggiunto due volte.", "schemas.fieldCannotBeUIField": "Il campo non può essere un campo UI.", diff --git a/backend/i18n/source/backend_nl.json b/backend/i18n/source/backend_nl.json index 40a9745d2..ed07d292f 100644 --- a/backend/i18n/source/backend_nl.json +++ b/backend/i18n/source/backend_nl.json @@ -7,7 +7,6 @@ "annotations_Required": "Het veld {name|lower} is verplicht.", "annotations_StringLength": "Het veld {name|lower} moet een string zijn met een maximale lengte van {max}.", "annotations_StringLengthMinimum": "Het veld {name|lower} moet een string zijn met een minimum lengte van {min} en een maximum lengte van {max}.", - "apps.alreadyArchieved": "App is al gearchiveerd.", "apps.clients.idAlreadyExists": "Er bestaat al een client met dezelfde id.", "apps.contributors.cannotChangeYourself": "Je kunt jouw eigen rol niet wijzigen.", "apps.contributors.maxReached": "Je heeft het maximale aantal bijdragers voor jouw plan bereikt.", @@ -28,8 +27,6 @@ "apps.roles.nameAlreadyExists": "Er bestaat al een rol met dezelfde naam.", "apps.roles.usedRoleByClientsNotRemovable": "Kan een rol niet verwijderen wanneer een client is toegewezen.", "apps.roles.usedRoleByContributorsNotRemovable": "Kan een rol niet verwijderen wanneer een bijdrager is toegewezen.", - "assets.assetAlreadyDeleted": "Asset is al verwijderd", - "assets.assetFolderAlreadyDeleted": "Assetmap is al verwijderd", "assets.folderNotFound": "Assetmap bestaat niet.", "assets.folderRecursion": "Kan map niet toevoegen aan zijn eigen kind.", "assets.maxSizeReached": "Je hebt jouw maximale assetgrootte bereikt.", @@ -126,7 +123,6 @@ "contents.bulkInsertQueryNotUnique": "Meer dan één inhoud komt overeen met de zoekopdracht.", "contents.draftNotCreateForUnpublished": "Je kunt alleen een nieuwe versie maken wanneer de inhoud is gepubliceerd.", "contents.draftToDeleteNotFound": "Er is niets te verwijderen.", - "contents.invalidArrayOfIds": "Ongeldig json-type, verwachte array van guid-strings.", "contents.invalidArrayOfObjects": "Ongeldig json-type, verwachte reeks objecten.", "contents.invalidArrayOfStrings": "Ongeldig json-type, verwachte reeks strings.", "contents.invalidBoolean": "Ongeldig json-type, verwachte boolean.", @@ -248,9 +244,7 @@ "history.schemas.updated": "bijgewerkt schema {[Name]}.", "history.statusChanged": "veranderde status van {[Schema]} inhoud in {[Status]}.", "login.githubPrivateEmail": "Jouw e-mailadres is ingesteld op privé in Github. Stel het in op openbaar om Github-login te gebruiken.", - "rules.alreadyDeleted": "Regel is al verwijderd.", "rules.ruleAlreadyRunning": "Er wordt al een andere regel uitgevoerd.", - "schemas.alreadyDeleted": "Schema is al verwijderd.", "schemas.dateTimeCalculatedDefaultAndDefaultError": "Berekende standaardwaarde en standaardwaarde kunnen niet samen worden gebruikt.", "schemas.duplicateFieldName": "Veld '{field}' is twee keer toegevoegd.", "schemas.fieldCannotBeUIField": "Veld mag geen UI-veld zijn.", diff --git a/backend/i18n/source/frontend_en.json b/backend/i18n/source/frontend_en.json index 45577deae..73118fb70 100644 --- a/backend/i18n/source/frontend_en.json +++ b/backend/i18n/source/frontend_en.json @@ -12,11 +12,11 @@ "apps.appNameWarning": "The app name cannot be changed later.", "apps.appsButtonCreate": "Apps Overview", "apps.appsButtonFallbackTitle": "Apps Overview", - "apps.archieve": "Archive App", - "apps.archieveConfirmText": "Do you really want to archive this App?", - "apps.archieveConfirmTitle": "Archive App", - "apps.archieveWarning": "Once you archive an app, there is no going back. Please be certain.", + "apps.archive": "Archive App", + "apps.archiveConfirmText": "Do you really want to archive this app?", + "apps.archiveConfirmTitle": "Archive App", "apps.archiveFailed": "Failed to archive app. Please reload.", + "apps.archiveWarning": "Once you archive an app, there is no going back. Please be certain.", "apps.create": "Create App", "apps.createBlankApp": "New App", "apps.createBlankAppDescription": "Create a new blank app without content and schemas.", diff --git a/backend/i18n/source/frontend_it.json b/backend/i18n/source/frontend_it.json index a7db499d6..5277abf10 100644 --- a/backend/i18n/source/frontend_it.json +++ b/backend/i18n/source/frontend_it.json @@ -12,11 +12,11 @@ "apps.appNameWarning": "Il nome della app non potrà essere cambiato in un secondo momento.", "apps.appsButtonCreate": "Nuova App", "apps.appsButtonFallbackTitle": "Lista App", - "apps.archieve": "Archivia l'App", - "apps.archieveConfirmText": "Rimuovi il pattern", - "apps.archieveConfirmTitle": "Sei sicuro di voler archiviare questa app?", - "apps.archieveWarning": "Una volta archiviata una App, non è possibile tornare indietro. Sii certo.", + "apps.archive": "Archivia l'App", + "apps.archiveConfirmText": "Rimuovi il pattern", + "apps.archiveConfirmTitle": "Sei sicuro di voler archiviare questa app?", "apps.archiveFailed": "Non è stato possibile archiviare l'app. Per favore ricarica.", + "apps.archiveWarning": "Una volta archiviata una App, non è possibile tornare indietro. Sii certo.", "apps.create": "Crea un'App", "apps.createBlankApp": "Nuova App.", "apps.createBlankAppDescription": "Crea una app vuota senza contenuti o schema.", diff --git a/backend/i18n/source/frontend_nl.json b/backend/i18n/source/frontend_nl.json index 4f0afdfb9..5ab379cad 100644 --- a/backend/i18n/source/frontend_nl.json +++ b/backend/i18n/source/frontend_nl.json @@ -12,11 +12,11 @@ "apps.appNameWarning": "De app-naam kan later niet worden gewijzigd.", "apps.appsButtonCreate": "Apps-overzicht", "apps.appsButtonFallbackTitle": "Apps-overzicht", - "apps.archieve": "App archiveren", - "apps.archieveConfirmText": "Patroon verwijderen", - "apps.archieveConfirmTitle": "Wil je deze app echt archiveren?", - "apps.archieveWarning": "Zodra je een app archiveert, is er geen weg meer terug. Wees alsjeblieft zeker.", + "apps.archive": "App archiveren", + "apps.archiveConfirmText": "Patroon verwijderen", + "apps.archiveConfirmTitle": "Wil je deze app echt archiveren?", "apps.archiveFailed": "Kan app niet archiveren. Laad opnieuw.", + "apps.archiveWarning": "Zodra je een app archiveert, is er geen weg meer terug. Wees alsjeblieft zeker.", "apps.create": "App maken", "apps.createBlankApp": "Nieuwe app.", "apps.createBlankAppDescription": "Maak een nieuwe lege app zonder inhoud en schema's.", diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs index 982082bdc..6666a8a46 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetFolderDomainObject.cs @@ -54,8 +54,6 @@ namespace Squidex.Domain.Apps.Entities.Assets public override Task ExecuteAsync(IAggregateCommand command) { - VerifyNotDeleted(); - switch (command) { case CreateAssetFolder createAssetFolder: @@ -123,13 +121,5 @@ namespace Squidex.Domain.Apps.Entities.Assets RaiseEvent(Envelope.Create(@event)); } - - private void VerifyNotDeleted() - { - if (Snapshot.IsDeleted) - { - throw new DomainException(T.Get("assets.assetFolderAlreadyDeleted")); - } - } } } diff --git a/backend/src/Squidex.Domain.Users/PwnedPasswordValidator.cs b/backend/src/Squidex.Domain.Users/PwnedPasswordValidator.cs index 9f34fdf65..ecd5125a6 100644 --- a/backend/src/Squidex.Domain.Users/PwnedPasswordValidator.cs +++ b/backend/src/Squidex.Domain.Users/PwnedPasswordValidator.cs @@ -29,6 +29,11 @@ namespace Squidex.Domain.Users public async Task ValidateAsync(UserManager manager, IdentityUser user, string password) { + if (string.IsNullOrWhiteSpace(password)) + { + return IdentityResult.Success; + } + try { var isBreached = await client.IsPasswordPwned(password); diff --git a/backend/src/Squidex.Infrastructure/DomainObjectConflictException.cs b/backend/src/Squidex.Infrastructure/DomainObjectConflictException.cs index 189769c4d..7c90dae9c 100644 --- a/backend/src/Squidex.Infrastructure/DomainObjectConflictException.cs +++ b/backend/src/Squidex.Infrastructure/DomainObjectConflictException.cs @@ -26,7 +26,7 @@ namespace Squidex.Infrastructure private static string FormatMessage(string id) { - return T.Get("exceptions.domainObjectDeleted", new { id }); + return T.Get("exceptions.domainObjectConflict", new { id }); } } } diff --git a/backend/src/Squidex.Shared/Texts.it.resx b/backend/src/Squidex.Shared/Texts.it.resx index 1285956db..fba3d0a5d 100644 --- a/backend/src/Squidex.Shared/Texts.it.resx +++ b/backend/src/Squidex.Shared/Texts.it.resx @@ -106,9 +106,6 @@ The field {0} must be a string with a minimum length of {1} and a maximum length of {2}. - - La App è stata già archiviata. - Un client con lo stesso id esiste già. @@ -169,12 +166,6 @@ Non è possibile rimuovere un ruolo quando questo è assegnato ad un collaboratore. - - La risorsa è stata già eliminata - - - La cartella delle risorse è stata già eliminata - La cartella delle risorse non esiste. @@ -463,9 +454,6 @@ Non c'è niente da eliminare. - - Errore nel json, atteso un array di string guid. - Errore nel json, attesp un array di objects. @@ -832,15 +820,9 @@ Il tuo indirizzo email è impostato su privato in Github. Impostalo come pubblico per poter utilizzare il login Github. - - La regola è stata già cancellata. - E' in esecuzione un'altra regola. - - Lo schema è stato già cancellato. - Il valore predefinito calcolato e il valore predefinito non possono essere utilizzati insieme. diff --git a/backend/src/Squidex.Shared/Texts.nl.resx b/backend/src/Squidex.Shared/Texts.nl.resx index d7b3e32b7..ae161559d 100644 --- a/backend/src/Squidex.Shared/Texts.nl.resx +++ b/backend/src/Squidex.Shared/Texts.nl.resx @@ -106,9 +106,6 @@ Het veld {0} moet een string zijn met een minimum lengte van {1} en een maximum lengte van {2}. - - App is al gearchiveerd. - Er bestaat al een client met dezelfde id. @@ -169,12 +166,6 @@ Kan een rol niet verwijderen wanneer een bijdrager is toegewezen. - - Asset is al verwijderd - - - Assetmap is al verwijderd - Assetmap bestaat niet. @@ -463,9 +454,6 @@ Er is niets te verwijderen. - - Ongeldig json-type, verwachte array van guid-strings. - Ongeldig json-type, verwachte reeks objecten. @@ -832,15 +820,9 @@ Jouw e-mailadres is ingesteld op privé in Github. Stel het in op openbaar om Github-login te gebruiken. - - Regel is al verwijderd. - Er wordt al een andere regel uitgevoerd. - - Schema is al verwijderd. - Berekende standaardwaarde en standaardwaarde kunnen niet samen worden gebruikt. diff --git a/backend/src/Squidex.Shared/Texts.resx b/backend/src/Squidex.Shared/Texts.resx index 28dcca1d2..df10f50cf 100644 --- a/backend/src/Squidex.Shared/Texts.resx +++ b/backend/src/Squidex.Shared/Texts.resx @@ -106,9 +106,6 @@ The field {0} must be a string with a minimum length of {1} and a maximum length of {2}. - - App has already been archived. - A client with the same id already exists. @@ -169,12 +166,6 @@ Cannot remove a role when a contributor is assigned. - - Asset has already been deleted - - - Asset folder has already been deleted - Asset folder does not exist. @@ -463,9 +454,6 @@ There is nothing to delete. - - Invalid json type, expected array of guid strings. - Invalid json type, expected array of objects. @@ -832,15 +820,9 @@ Your email address is set to private in Github. Please set it to public to use Github login. - - Rule has already been deleted. - Another rule is already running. - - Schema has already been deleted. - Calculated default value and default value cannot be used together. diff --git a/backend/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs b/backend/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs index 60c709362..c4ae98280 100644 --- a/backend/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs +++ b/backend/src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Concurrent; using System.Globalization; using System.IO; +using System.Net; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -33,20 +34,23 @@ namespace Squidex.Areas.Frontend.Middlewares return context.Request.Path.Value.EndsWith(".html", StringComparison.OrdinalIgnoreCase); } - public static bool IsHtml(this HttpContext context) + public static bool IsNotModified(this HttpResponse response) { - return context.Response.ContentType?.ToLower().Contains("text/html") == true; + return response.StatusCode == (int)HttpStatusCode.NotModified; } - public static string AdjustHtml(this string html, HttpContext httpContext) + public static string AdjustBase(this string html, HttpContext httpContext) { - var result = html; - if (httpContext.Request.PathBase.HasValue) { - result = result.Replace("", $""); + html = html.Replace("", $""); } + return html; + } + + public static string AddOptions(this string html, HttpContext httpContext) + { var uiOptions = httpContext.RequestServices.GetService>()?.Value; if (uiOptions != null) @@ -72,10 +76,10 @@ namespace Squidex.Areas.Frontend.Middlewares var texts = GetText(CultureInfo.CurrentUICulture.Name); - result = result.Replace("", $"\n"); + html = html.Replace("", $"\n"); } - return result; + return html; } private static string GetText(string culture) diff --git a/backend/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs b/backend/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs index 4ba2db152..25c055be7 100644 --- a/backend/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs +++ b/backend/src/Squidex/Areas/Frontend/Middlewares/IndexMiddleware.cs @@ -23,7 +23,7 @@ namespace Squidex.Areas.Frontend.Middlewares public async Task InvokeAsync(HttpContext context) { - if (context.IsHtmlPath() && context.Response.StatusCode != 304) + if (context.IsHtmlPath() && !context.Response.IsNotModified()) { var responseBuffer = new MemoryStream(); var responseBody = context.Response.Body; @@ -32,13 +32,18 @@ namespace Squidex.Areas.Frontend.Middlewares await next(context); - if (context.Response.StatusCode != 304) + if (!context.Response.IsNotModified()) { context.Response.Body = responseBody; var html = Encoding.UTF8.GetString(responseBuffer.ToArray()); - html = html.AdjustHtml(context); + html = html.AdjustBase(context); + + if (context.IsIndex()) + { + html = html.AddOptions(context); + } context.Response.ContentLength = Encoding.UTF8.GetByteCount(html); context.Response.Body = responseBody; diff --git a/backend/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs b/backend/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs index 7d2ac538c..694167c1f 100644 --- a/backend/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs +++ b/backend/src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.IO; +using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -26,7 +27,7 @@ namespace Squidex.Areas.Frontend.Middlewares public async Task InvokeAsync(HttpContext context) { - if (context.IsIndex() && context.Response.StatusCode != 304) + if (context.IsIndex() && !context.Response.IsNotModified()) { var handler = new HttpClientHandler { @@ -43,35 +44,12 @@ namespace Squidex.Areas.Frontend.Middlewares { var html = await result.Content.ReadAsStringAsync(); - html = html.AdjustHtml(context); + html = html.AdjustBase(context); await context.Response.WriteAsync(html); } } } - else if (context.IsHtmlPath() && context.Response.StatusCode != 304) - { - var responseBuffer = new MemoryStream(); - var responseBody = context.Response.Body; - - context.Response.Body = responseBuffer; - - await next(context); - - if (context.Response.StatusCode != 304) - { - context.Response.Body = responseBody; - - var html = Encoding.UTF8.GetString(responseBuffer.ToArray()); - - html = html.AdjustHtml(context); - - context.Response.ContentLength = Encoding.UTF8.GetByteCount(html); - context.Response.Body = responseBody; - - await context.Response.WriteAsync(html); - } - } else { await next(context); diff --git a/backend/src/Squidex/Areas/Frontend/Startup.cs b/backend/src/Squidex/Areas/Frontend/Startup.cs index 2d8edf0ac..6c3f5f74c 100644 --- a/backend/src/Squidex/Areas/Frontend/Startup.cs +++ b/backend/src/Squidex/Areas/Frontend/Startup.cs @@ -52,14 +52,12 @@ namespace Squidex.Areas.Frontend return next(); }); + app.UseMiddleware(); + if (environment.IsDevelopment()) { app.UseMiddleware(); } - else - { - app.UseMiddleware(); - } app.UseStaticFiles(new StaticFileOptions { diff --git a/frontend/app/features/apps/pages/apps-page.component.html b/frontend/app/features/apps/pages/apps-page.component.html index 7cea6473d..66209487f 100644 --- a/frontend/app/features/apps/pages/apps-page.component.html +++ b/frontend/app/features/apps/pages/apps-page.component.html @@ -1,8 +1,8 @@ -
+
-

{{ 'apps.welcomeTitle' | sqxTranslate: { user: authState.user?.displayName } }}

+

{{ 'apps.welcomeTitle' | sqxTranslate: { user: user.displayName } }}

{{ 'apps.welcomeSubtitle' | sqxTranslate }} diff --git a/frontend/app/features/schemas/pages/schema/common/schema-edit-form.component.html b/frontend/app/features/schemas/pages/schema/common/schema-edit-form.component.html index 4f014effe..67074d7cd 100644 --- a/frontend/app/features/schemas/pages/schema/common/schema-edit-form.component.html +++ b/frontend/app/features/schemas/pages/schema/common/schema-edit-form.component.html @@ -37,7 +37,7 @@ - {{ 'schemas.contentsSidebarUrl' | sqxTranslate }} + {{ 'schemas.contentsSidebarUrlHint' | sqxTranslate }}
diff --git a/frontend/app/features/settings/pages/more/more-page.component.html b/frontend/app/features/settings/pages/more/more-page.component.html index 408f9e91f..09ee2551a 100644 --- a/frontend/app/features/settings/pages/more/more-page.component.html +++ b/frontend/app/features/settings/pages/more/more-page.component.html @@ -90,18 +90,18 @@
-
{{ 'apps.archieve' | sqxTranslate }}
+
{{ 'apps.archive' | sqxTranslate }}
- {{ 'apps.archieveWarning' | sqxTranslate }} + {{ 'apps.archiveWarning' | sqxTranslate }}
diff --git a/frontend/app/features/settings/pages/roles/role.component.html b/frontend/app/features/settings/pages/roles/role.component.html index e50a25b6c..21f0efdc9 100644 --- a/frontend/app/features/settings/pages/roles/role.component.html +++ b/frontend/app/features/settings/pages/roles/role.component.html @@ -81,7 +81,7 @@
+ placeholder="{{ 'roles.permissionsPlaceholder' | sqxTranslate }}">
diff --git a/frontend/app/framework/angular/routers/router-2-state.spec.ts b/frontend/app/framework/angular/routers/router-2-state.spec.ts index 0b0b9fde6..500fcf0ea 100644 --- a/frontend/app/framework/angular/routers/router-2-state.spec.ts +++ b/frontend/app/framework/angular/routers/router-2-state.spec.ts @@ -23,17 +23,17 @@ describe('Router2State', () => { synchronizer.writeValue(value, params); - expect(params['key']).toEqual('my-string'); + expect(params).toEqual({ key: 'my-string' }); }); - it('should not write value to route when not a string', () => { + it('Should write undefined when not a string', () => { const params: Params = {}; const value = 123; synchronizer.writeValue(value, params); - expect(params).toEqual({}); + expect(params).toEqual({ key: undefined }); }); it('should get string from route', () => { @@ -60,27 +60,27 @@ describe('Router2State', () => { synchronizer.writeValue(value, params); - expect(params['key']).toEqual('flag1,flag2'); + expect(params).toEqual({ key: 'flag1,flag2' }); }); - it('should write empty object to route', () => { + it('Should write undefined when empty', () => { const params: Params = {}; const value = {}; synchronizer.writeValue(value, params); - expect(params['key']).toEqual(''); + expect(params).toEqual({ key: undefined }); }); - it('should not write value to route when not an object', () => { + it('Should write undefined when not an object', () => { const params: Params = {}; const value = 123; synchronizer.writeValue(value, params); - expect(params).toEqual({}); + expect(params).toEqual({ key: undefined }); }); it('should get object from route', () => { @@ -117,45 +117,44 @@ describe('Router2State', () => { synchronizer.writeValue(value, params); - expect(params['page']).toEqual('10'); - expect(params['take']).toEqual('20'); + expect(params).toEqual({ take: '20', page: '10' }); localStore.verify(x => x.setInt('contents.pageSize', 20), Times.once()); }); - it('should not write page if zero', () => { + it('Should write undefined when page number is zero', () => { const params: Params = {}; const value = new Pager(0, 0, 20, true); synchronizer.writeValue(value, params); - expect(params['page']).toBeUndefined(); - expect(params['take']).toEqual('20'); + expect(params).toEqual({ take: '20', page: undefined }); localStore.verify(x => x.setInt('contents.pageSize', 20), Times.once()); }); - it('should not write value to route when not pager', () => { + it('should write undefined when value not a pager', () => { const params: Params = {}; const value = 123; synchronizer.writeValue(value, params); - expect(params).toEqual({}); + expect(params).toEqual({ take: undefined, page: undefined }); localStore.verify(x => x.setInt('contents.pageSize', 20), Times.never()); }); - it('should not write value to route when null', () => { + it('should write undefined when value is null', () => { const params: Params = {}; const value = null; synchronizer.writeValue(value, params); - expect(params).toEqual({}); + expect(params).toEqual({ take: undefined, page: undefined }); + localStore.verify(x => x.setInt('contents.pageSize', 20), Times.never()); }); diff --git a/frontend/app/framework/angular/routers/router-2-state.ts b/frontend/app/framework/angular/routers/router-2-state.ts index 4b5abf78e..d47616305 100644 --- a/frontend/app/framework/angular/routers/router-2-state.ts +++ b/frontend/app/framework/angular/routers/router-2-state.ts @@ -54,6 +54,9 @@ export class PagerSynchronizer implements RouteSynchronizer { } public writeValue(state: any, params: Params) { + params['page'] = undefined; + params['take'] = undefined; + if (Types.is(state, Pager)) { if (state.page > 0) { params['page'] = state.page.toString(); @@ -81,6 +84,8 @@ export class StringSynchronizer implements RouteSynchronizer { } public writeValue(state: any, params: Params) { + params[this.name] = undefined; + if (Types.isString(state)) { params[this.name] = state; } @@ -110,10 +115,14 @@ export class StringKeysSynchronizer implements RouteSynchronizer { } public writeValue(state: any, params: Params) { + params[this.name] = undefined; + if (Types.isObject(state)) { const value = Object.keys(state).join(','); - params[this.name] = value; + if (value.length > 0) { + params[this.name] = value; + } } } } diff --git a/frontend/app/shared/components/assets/asset-folder.component.scss b/frontend/app/shared/components/assets/asset-folder.component.scss index fbd449dfd..a2d87a346 100644 --- a/frontend/app/shared/components/assets/asset-folder.component.scss +++ b/frontend/app/shared/components/assets/asset-folder.component.scss @@ -14,6 +14,7 @@ img { & { border-bottom-width: 1px; border-width: 1px; + cursor: default; width: $asset-width; } diff --git a/frontend/app/shared/state/query.spec.ts b/frontend/app/shared/state/query.spec.ts index f2ead7f8b..0165115ca 100644 --- a/frontend/app/shared/state/query.spec.ts +++ b/frontend/app/shared/state/query.spec.ts @@ -1,3 +1,4 @@ +import { Params } from '@angular/router'; /* * Squidex Headless CMS * @@ -6,7 +7,7 @@ */ import { Query } from '@app/shared/internal'; -import { equalsQuery } from './query'; +import { equalsQuery, QueryFullTextSynchronizer, QuerySynchronizer } from './query'; describe('equalsQuery', () => { it('should return true when comparing with empty query', () => { @@ -53,4 +54,108 @@ describe('equalsQuery', () => { expect(equalsQuery(lhs, rhs)).toBeTruthy(); }); +}); + +describe('QueryFullTextSynchronizer', () => { + const synchronizer = new QueryFullTextSynchronizer(); + + it('should write full text to route', () => { + const params: Params = {}; + + const value = { fullText: 'my-query' }; + + synchronizer.writeValue(value, params); + + expect(params).toEqual({ query: 'my-query' }); + }); + + it('Should write undefined when not a query', () => { + const params: Params = {}; + + const value = 123; + + synchronizer.writeValue(value, params); + + expect(params).toEqual({ query: undefined }); + }); + + it('Should write undefined query has no full text', () => { + const params: Params = {}; + + const value = { fullText: '' }; + + synchronizer.writeValue(value, params); + + expect(params).toEqual({ query: undefined }); + }); + + it('should get query from route', () => { + const params: Params = { + query: 'my-query' + }; + + const value = synchronizer.getValue(params); + + expect(value).toEqual({ fullText: 'my-query' }); + }); + + it('should get query as undefined from route', () => { + const params: Params = {}; + + const value = synchronizer.getValue(params); + + expect(value).toBeUndefined(); + }); +}); + +describe('QuerySynchronizer', () => { + const synchronizer = new QuerySynchronizer(); + + it('should write query to route', () => { + const params: Params = {}; + + const value = { filter: 'my-filter' }; + + synchronizer.writeValue(value, params); + + expect(params).toEqual({ query: '{"filter":"my-filter","sort":[]}' }); + }); + + it('Should write undefined when not a query', () => { + const params: Params = {}; + + const value = 123; + + synchronizer.writeValue(value, params); + + expect(params).toEqual({ query: undefined }); + }); + + it('should get query from route', () => { + const params: Params = { + query: '{"filter":"my-filter"}' + }; + + const value = synchronizer.getValue(params) as any; + + expect(value).toEqual({ filter: 'my-filter' }); + }); + + it('should get query full text from route', () => { + const params: Params = { + query: 'my-query' + }; + + const value = synchronizer.getValue(params); + + expect(value).toEqual({ fullText: 'my-query' }); + }); + + it('should get query as undefined from route', () => { + const params: Params = {}; + + const value = synchronizer.getValue(params); + + expect(value).toBeUndefined(); + }); }); \ No newline at end of file diff --git a/frontend/app/shared/state/query.ts b/frontend/app/shared/state/query.ts index 79c0cfb4a..f3d6e4385 100644 --- a/frontend/app/shared/state/query.ts +++ b/frontend/app/shared/state/query.ts @@ -128,6 +128,8 @@ export class QueryFullTextSynchronizer implements RouteSynchronizer { } public writeValue(state: any, params: Params) { + params['query'] = undefined; + if (Types.isObject(state) && Types.isString(state.fullText) && state.fullText.length > 0) { params['query'] = state.fullText; } @@ -144,6 +146,8 @@ export class QuerySynchronizer implements RouteSynchronizer { } public writeValue(state: any, params: Params) { + params['query'] = undefined; + if (Types.isObject(state)) { params['query'] = serializeQuery(state); }