From a72d238e30f1469baf2db1c468c56df02cb7a70e Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Thu, 10 Mar 2022 09:34:08 +0100 Subject: [PATCH] Gallery (#855) * Remove app templates. * Refactoring and new service. * Many fixes. * Added missing files. --- .../Samples/Middleware/TemplateInstance.cs | 48 ---- .../Samples/Middleware/TemplateMiddleware.cs | 63 ---- .../Samples/Middleware/TemplatePlugin.cs | 25 -- backend/i18n/frontend_en.json | 3 + backend/i18n/frontend_it.json | 3 + backend/i18n/frontend_nl.json | 3 + backend/i18n/frontend_zh.json | 3 + backend/i18n/source/frontend_en.json | 3 + .../AlwaysCreateClientCommandMiddleware.cs | 2 +- .../Templates/Builders/ArrayFieldBuilder.cs | 144 ---------- .../Templates/Builders/AssetFieldBuilder.cs | 20 -- .../Templates/Builders/BooleanFieldBuilder.cs | 20 -- .../Builders/ComponentFieldBuilder.cs | 20 -- .../Builders/ComponentsFieldBuilder.cs | 20 -- .../Builders/DateTimeFieldBuilder.cs | 20 -- .../Apps/Templates/Builders/FieldBuilder.cs | 97 ------- .../Templates/Builders/JsonFieldBuilder.cs | 20 -- .../Templates/Builders/NumberFieldBuilder.cs | 20 -- .../Builders/ReferencesFieldBuilder.cs | 20 -- .../Apps/Templates/Builders/SchemaBuilder.cs | 203 ------------- .../Templates/Builders/StringFieldBuilder.cs | 20 -- .../Templates/Builders/TagsFieldBuilder.cs | 20 -- .../Apps/Templates/Builders/UIFieldBuilder.cs | 20 -- .../Apps/Templates/CreateBlog.cs | 127 --------- .../Apps/Templates/CreateProfile.cs | 269 ------------------ .../Apps/Templates/DefaultScripts.cs | 29 -- .../Templates/{ITemplate.cs => Template.cs} | 7 +- .../Templates/TemplateCommandMiddleware.cs | 49 ---- .../Apps/Templates/TemplatesClient.cs | 69 +++++ backend/src/Squidex.Web/Resource.cs | 14 +- .../Controllers/Apps/AppAssetsController.cs | 2 +- .../Apps/AppLanguagesController.cs | 2 +- .../Controllers/Apps/AppRolesController.cs | 2 +- .../Controllers/Apps/AppSettingsController.cs | 2 +- .../Api/Controllers/Apps/AppsController.cs | 6 +- .../Api/Controllers/Apps/Models/AppDto.cs | 2 +- .../Controllers/Apps/Models/AppLanguageDto.cs | 2 +- .../Apps/Models/AppLanguagesDto.cs | 4 +- .../Controllers/Apps/Models/AppSettingsDto.cs | 4 +- .../Apps/Models/AssetScriptsDto.cs | 2 +- .../Controllers/Apps/Models/ContributorDto.cs | 2 +- .../Apps/Models/ContributorsDto.cs | 2 +- .../Controllers/Apps/Models/CreateAppDto.cs | 5 - .../Api/Controllers/Apps/Models/EditorDto.cs | 6 +- .../Api/Controllers/Apps/Models/PatternDto.cs | 4 +- .../Api/Controllers/Apps/Models/RoleDto.cs | 2 +- .../Api/Controllers/Apps/Models/RolesDto.cs | 4 +- .../Controllers/Apps/Models/WorkflowDto.cs | 4 +- .../Apps/Models/WorkflowStepDto.cs | 14 +- .../Apps/Models/WorkflowTransitionDto.cs | 6 +- .../Controllers/Apps/Models/WorkflowsDto.cs | 2 +- .../Assets/AssetFoldersController.cs | 4 +- .../Controllers/Assets/AssetsController.cs | 12 +- .../Api/Controllers/Assets/Models/AssetDto.cs | 44 +-- .../Assets/Models/AssetFolderDto.cs | 18 +- .../Assets/Models/AssetFoldersDto.cs | 18 +- .../Controllers/Assets/Models/AssetsDto.cs | 20 +- .../Controllers/Backups/BackupsController.cs | 2 +- .../Backups/Models/BackupJobDto.cs | 2 +- .../Backups/Models/BackupJobsDto.cs | 4 +- .../Backups/Models/RestoreJobDto.cs | 2 +- .../Controllers/Backups/RestoreController.cs | 2 +- .../Areas/Api/Controllers/BulkResultDto.cs | 2 +- .../Comments/CommentsController.cs | 4 +- .../Controllers/Comments/Models/CommentDto.cs | 8 +- .../Comments/Models/CommentsDto.cs | 14 +- .../UserNotificationsController.cs | 2 +- .../Contents/ContentsController.cs | 10 +- .../Controllers/Contents/Models/ContentDto.cs | 4 +- .../Contents/Models/ContentsDto.cs | 4 +- .../Contents/Models/StatusInfoDto.cs | 6 +- .../EventConsumersController.cs | 8 +- .../EventConsumers/Models/EventConsumerDto.cs | 2 +- .../Models/EventConsumersDto.cs | 4 +- .../Controllers/History/HistoryController.cs | 2 +- .../History/Models/HistoryEventDto.cs | 6 +- .../Areas/Api/Controllers/LanguageDto.cs | 6 +- .../Languages/LanguagesController.cs | 2 +- .../Controllers/Plans/AppPlansController.cs | 2 +- .../Controllers/Plans/Models/AppPlansDto.cs | 8 +- .../Api/Controllers/Plans/Models/PlanDto.cs | 6 +- .../Converters/RuleTriggerDtoFactory.cs | 2 +- .../Api/Controllers/Rules/Models/RuleDto.cs | 2 +- .../Rules/Models/RuleElementDto.cs | 2 +- .../Controllers/Rules/Models/RuleEventDto.cs | 2 +- .../Controllers/Rules/Models/RuleEventsDto.cs | 4 +- .../Api/Controllers/Rules/Models/RulesDto.cs | 2 +- .../Rules/Models/SimulatedRuleEventDto.cs | 2 +- .../Rules/Models/SimulatedRuleEventsDto.cs | 4 +- .../ContentChangedRuleTriggerSchemaDto.cs | 6 +- .../Api/Controllers/Rules/RulesController.cs | 8 +- .../Controllers/Schemas/Models/FieldDto.cs | 6 +- .../Schemas/Models/FieldRuleDto.cs | 2 +- .../Controllers/Schemas/Models/SchemaDto.cs | 6 +- .../Controllers/Schemas/Models/SchemasDto.cs | 4 +- .../Schemas/SchemaFieldsController.cs | 2 +- .../Controllers/Schemas/SchemasController.cs | 6 +- .../Search/Models/SearchResultDto.cs | 14 +- .../Controllers/Search/SearchController.cs | 2 +- .../Statistics/Models/CallsUsageDtoDto.cs | 4 +- .../Statistics/Models/CallsUsagePerDateDto.cs | 2 +- .../Models/StorageUsagePerDateDto.cs | 2 +- .../Statistics/UsagesController.cs | 4 +- .../Templates/Models/TemplateDetailsDto.cs | 40 +++ .../Templates/Models/TemplateDto.cs | 51 ++++ .../Templates/Models/TemplatesDto.cs | 37 +++ .../Templates/TemplatesController.cs | 75 +++++ .../Translations/Models/TranslationDto.cs | 2 +- .../Translations/TranslationsController.cs | 2 +- .../Controllers/Users/Models/ResourcesDto.cs | 2 +- .../Api/Controllers/Users/Models/UserDto.cs | 8 +- .../Api/Controllers/Users/Models/UsersDto.cs | 4 +- .../Users/UserManagementController.cs | 12 +- .../Api/Controllers/Users/UsersController.cs | 6 +- .../Squidex/Config/Domain/CommandsServices.cs | 11 +- .../Squidex/Config/Domain/ContentsServices.cs | 4 + .../src/Squidex/wwwroot/images/add-blog.svg | 38 --- .../Squidex/wwwroot/images/add-identity.svg | 27 -- .../Squidex/wwwroot/images/add-profile.svg | 26 -- ...lwaysCreateClientCommandMiddlewareTests.cs | 2 +- .../Apps/Templates/TemplatesClientTests.cs | 56 ++++ .../Apps/Templates/TemplatesTests.cs | 47 --- frontend/.eslintrc.js | 17 +- frontend/package-lock.json | 27 ++ frontend/package.json | 1 + .../guards/user-must-exist.guard.ts | 3 +- .../services/event-consumers.service.spec.ts | 2 +- .../services/event-consumers.service.ts | 28 +- .../administration/services/users.service.ts | 14 +- .../state/event-consumers.state.spec.ts | 6 +- .../administration/state/users.forms.ts | 2 +- .../pages/graphql/graphql-page.component.ts | 7 +- .../apps/pages/apps-page.component.html | 36 +-- .../apps/pages/apps-page.component.ts | 4 +- .../pages/content/content-page.component.ts | 2 +- .../reference-dropdown.component.ts | 2 +- .../references/references-editor.component.ts | 2 +- .../references/references-tags.component.ts | 2 +- .../fields/types/boolean-ui.component.ts | 2 +- .../fields/types/date-time-ui.component.ts | 2 +- .../fields/types/number-ui.component.ts | 2 +- .../fields/types/references-ui.component.ts | 2 +- .../fields/types/string-ui.component.ts | 2 +- .../types/string-validation.component.ts | 2 +- .../schema/fields/types/tags-ui.component.ts | 2 +- .../src/app/features/settings/declarations.ts | 2 + frontend/src/app/features/settings/module.ts | 12 +- .../pages/templates/template.component.html | 26 ++ .../pages/templates/template.component.scss | 17 ++ .../pages/templates/template.component.ts | 57 ++++ .../templates/templates-page.component.html | 25 ++ .../templates/templates-page.component.scss | 0 .../templates/templates-page.component.ts | 37 +++ .../pages/workflows/workflow.component.ts | 11 +- .../settings/settings-area.component.html | 5 + .../angular/forms/confirm-click.directive.ts | 4 +- .../framework/angular/forms/copy.directive.ts | 1 + .../forms/editors/code-editor.component.ts | 3 +- .../angular/http/caching.interceptor.ts | 3 +- .../framework/angular/http/http-extensions.ts | 3 +- .../angular/http/loading.interceptor.ts | 3 +- .../app/framework/angular/layout.component.ts | 2 +- .../framework/angular/stateful.component.ts | 3 +- .../framework/services/analytics.service.ts | 2 +- .../app/framework/services/dialog.service.ts | 2 + .../app/framework/services/loading.service.ts | 3 +- .../framework/services/message-bus.service.ts | 3 +- frontend/src/app/framework/utils/keys.ts | 2 + .../app/framework/utils/rxjs-extensions.ts | 3 +- .../shared/components/app-form.component.html | 8 +- .../shared/components/app-form.component.ts | 9 +- .../contents/content-list-cell.directive.ts | 2 +- .../forms/geolocation-editor.component.ts | 2 +- .../queries/filter-comparison.component.ts | 2 +- .../interceptors/auth.interceptor.spec.ts | 4 +- frontend/src/app/shared/internal.ts | 3 + frontend/src/app/shared/module.ts | 4 +- .../shared/services/app-languages.service.ts | 8 +- .../app/shared/services/apps.service.spec.ts | 10 +- .../src/app/shared/services/apps.service.ts | 6 +- .../shared/services/assets.service.spec.ts | 20 +- .../src/app/shared/services/assets.service.ts | 40 +-- .../shared/services/backups.service.spec.ts | 10 +- .../app/shared/services/backups.service.ts | 14 +- .../app/shared/services/clients.service.ts | 8 +- .../app/shared/services/comments.service.ts | 49 ++-- .../app/shared/services/contents.service.ts | 43 ++- .../shared/services/contributors.service.ts | 10 +- .../app/shared/services/help.service.spec.ts | 2 + .../app/shared/services/history.service.ts | 22 +- .../app/shared/services/languages.service.ts | 13 +- .../src/app/shared/services/news.service.ts | 22 +- .../src/app/shared/services/plans.service.ts | 52 ++-- .../src/app/shared/services/roles.service.ts | 2 +- .../src/app/shared/services/rules.service.ts | 46 +-- .../app/shared/services/schemas.service.ts | 6 +- .../src/app/shared/services/search.service.ts | 22 +- .../services/stock-photo.service.spec.ts | 2 + .../shared/services/stock-photo.service.ts | 17 +- .../shared/services/templates.service.spec.ts | 128 +++++++++ .../app/shared/services/templates.service.ts | 83 ++++++ .../shared/services/translations.service.ts | 7 +- .../app/shared/services/ui.service.spec.ts | 2 + .../src/app/shared/services/usages.service.ts | 73 ++--- .../shared/services/users-provider.service.ts | 12 +- .../src/app/shared/services/users.service.ts | 24 +- .../app/shared/services/workflows.service.ts | 6 +- frontend/src/app/shared/state/apps.forms.ts | 2 +- .../app/shared/state/asset-uploader.state.ts | 26 +- frontend/src/app/shared/state/assets.forms.ts | 2 +- .../src/app/shared/state/assets.state.spec.ts | 2 +- .../src/app/shared/state/backups.forms.ts | 2 +- .../src/app/shared/state/clients.forms.ts | 2 +- .../src/app/shared/state/comments.form.ts | 2 +- .../app/shared/state/contents.forms.spec.ts | 4 +- .../src/app/shared/state/contents.forms.ts | 5 +- .../app/shared/state/contributors.forms.ts | 2 +- .../src/app/shared/state/languages.forms.ts | 2 +- frontend/src/app/shared/state/resolvers.ts | 2 +- frontend/src/app/shared/state/roles.forms.ts | 2 +- frontend/src/app/shared/state/rules.forms.ts | 2 +- .../src/app/shared/state/schema-tag-source.ts | 4 +- .../src/app/shared/state/schemas.forms.ts | 2 +- .../app/shared/state/table-settings.spec.ts | 2 +- .../app/shared/state/template.state.spec.ts | 67 +++++ .../src/app/shared/state/templates.state.ts | 76 +++++ .../src/app/shared/state/workflows.forms.ts | 2 +- frontend/src/app/theme/_bootstrap.scss | 18 ++ frontend/src/app/theme/_common.scss | 18 ++ frontend/src/app/theme/_mixins.scss | 2 +- 230 files changed, 1588 insertions(+), 2077 deletions(-) delete mode 100644 backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs delete mode 100644 backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs delete mode 100644 backend/extensions/Squidex.Extensions/Samples/Middleware/TemplatePlugin.cs rename backend/src/Squidex.Domain.Apps.Entities/Apps/{Templates => }/AlwaysCreateClientCommandMiddleware.cs (95%) delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs rename backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/{ITemplate.cs => Template.cs} (72%) delete mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplatesClient.cs create mode 100644 backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDetailsDto.cs create mode 100644 backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDto.cs create mode 100644 backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplatesDto.cs create mode 100644 backend/src/Squidex/Areas/Api/Controllers/Templates/TemplatesController.cs delete mode 100644 backend/src/Squidex/wwwroot/images/add-blog.svg delete mode 100644 backend/src/Squidex/wwwroot/images/add-identity.svg delete mode 100644 backend/src/Squidex/wwwroot/images/add-profile.svg rename backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/{Templates => }/AlwaysCreateClientCommandMiddlewareTests.cs (95%) create mode 100644 backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesClientTests.cs delete mode 100644 backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs create mode 100644 frontend/src/app/features/settings/pages/templates/template.component.html create mode 100644 frontend/src/app/features/settings/pages/templates/template.component.scss create mode 100644 frontend/src/app/features/settings/pages/templates/template.component.ts create mode 100644 frontend/src/app/features/settings/pages/templates/templates-page.component.html create mode 100644 frontend/src/app/features/settings/pages/templates/templates-page.component.scss create mode 100644 frontend/src/app/features/settings/pages/templates/templates-page.component.ts create mode 100644 frontend/src/app/shared/services/templates.service.spec.ts create mode 100644 frontend/src/app/shared/services/templates.service.ts create mode 100644 frontend/src/app/shared/state/template.state.spec.ts create mode 100644 frontend/src/app/shared/state/templates.state.ts diff --git a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs b/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs deleted file mode 100644 index 0bdcb9716..000000000 --- a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs +++ /dev/null @@ -1,48 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Apps.Templates; -using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; - -namespace Squidex.Extensions.Samples.Middleware -{ - public class TemplateInstance : ITemplate - { - public string Name { get; } = "custom2"; - - public Task RunAsync(PublishTemplate publish) - { - var schema = - SchemaBuilder.Create("Blogs") - .AddString("Title", f => f - .Properties(p => p with - { - MaxLength = 100 - }) - .Required()) - .AddString("Slug", f => f - .Properties(p => p with - { - MaxLength = 100 - }) - .Required() - .Disabled()) - .AddString("Text", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.RichText, - MaxLength = 1000, - MinLength = 200 - }) - .Required()) - .Build(); - - return publish(schema); - } - } -} diff --git a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs b/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs deleted file mode 100644 index c3bb49fea..000000000 --- a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs +++ /dev/null @@ -1,63 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities; -using Squidex.Domain.Apps.Entities.Apps.Commands; -using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; - -namespace Squidex.Extensions.Samples.Middleware -{ - public sealed class TemplateMiddleware : ICustomCommandMiddleware - { - public async Task HandleAsync(CommandContext context, NextDelegate next) - { - await next(context); - - if (context.Command is CreateApp createApp && context.IsCompleted && createApp.Template == "custom") - { - var appId = NamedId.Of(createApp.AppId, createApp.Name); - - var publish = new Func(command => - { - command.AppId = appId; - - return context.CommandBus.PublishAsync(command); - }); - - var schema = - SchemaBuilder.Create("Pages") - .AddString("Title", f => f - .Properties(p => p with - { - MaxLength = 100 - }) - .Required()) - .AddString("Slug", f => f - .Properties(p => p with - { - MaxLength = 100 - }) - .Required() - .Disabled()) - .AddString("Text", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.RichText, - MaxLength = 1000, - MinLength = 200 - }) - .Required()) - .Build(); - - await publish(schema); - } - } - } -} diff --git a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplatePlugin.cs b/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplatePlugin.cs deleted file mode 100644 index bae84baa6..000000000 --- a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplatePlugin.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Squidex.Domain.Apps.Entities.Apps.Templates; -using Squidex.Infrastructure.Commands; -using Squidex.Infrastructure.Plugins; - -namespace Squidex.Extensions.Samples.Middleware -{ - public sealed class TemplatePlugin : IPlugin - { - public void ConfigureServices(IServiceCollection services, IConfiguration config) - { - services.AddSingleton(); - - services.AddSingleton(); - } - } -} diff --git a/backend/i18n/frontend_en.json b/backend/i18n/frontend_en.json index 66d6463cb..e75dd5cfe 100644 --- a/backend/i18n/frontend_en.json +++ b/backend/i18n/frontend_en.json @@ -380,6 +380,7 @@ "common.tagAddSchema": ", to add schema", "common.tags": "Tags", "common.tagsAll": "All tags", + "common.templates": "Templates", "common.time": "Time", "common.to": "To", "common.update": "Update", @@ -979,6 +980,8 @@ "start.loginHint": "The login button will open a new popup. Once you are logged in successful we will redirect you to the Squidex management portal.", "start.madeBy": "Proudly made by", "start.madeByCopyright": "Sebastian Stehle and Contributors, 2016-2021", + "templates.cliHint": "Download the CLI at https://github.com/squidex/squidex-samples to use the templates.", + "templates.reloaded": "Templates reloaded.", "tour.joinForum": "Join our Forum", "tour.joinGithub": "Join us on Github", "tour.skip": "Skip Tour", diff --git a/backend/i18n/frontend_it.json b/backend/i18n/frontend_it.json index 38e3a035e..b9d6f1986 100644 --- a/backend/i18n/frontend_it.json +++ b/backend/i18n/frontend_it.json @@ -380,6 +380,7 @@ "common.tagAddSchema": ", aggiungi schema", "common.tags": "Tag", "common.tagsAll": "Tutti i tag", + "common.templates": "Templates", "common.time": "Ora", "common.to": "To", "common.update": "Aggiorna", @@ -979,6 +980,8 @@ "start.loginHint": "Il pulsante per accedere aprirà un popup. Una volta effettuato l'accesso sarai indirizzato al portale per la gestione di Squidex.", "start.madeBy": "Realizzato con orgoglio da", "start.madeByCopyright": "Sebastian Stehle e Collaboratori, 2016-2020", + "templates.cliHint": "Download the CLI at https://github.com/squidex/squidex-samples to use the templates.", + "templates.reloaded": "Templates reloaded.", "tour.joinForum": "Unisciti al nostro Forum", "tour.joinGithub": "Unisciti a Github", "tour.skip": "Salta il Tour", diff --git a/backend/i18n/frontend_nl.json b/backend/i18n/frontend_nl.json index fc027ab47..e0bd94c16 100644 --- a/backend/i18n/frontend_nl.json +++ b/backend/i18n/frontend_nl.json @@ -380,6 +380,7 @@ "common.tagAddSchema": ", om schema toe te voegen", "common.tags": "Tags", "common.tagsAll": "Alle tags", + "common.templates": "Templates", "common.time": "Tijd", "common.to": "Naar", "common.update": "Update", @@ -979,6 +980,8 @@ "start.loginHint": "De login-knop opent een nieuwe pop-up. Zodra je succesvol bent ingelogd, zullen we je doorverwijzen naar het Squidex beheerportaal.", "start.madeBy": "Met trots gemaakt door", "start.madeByCopyright": "Sebastian Stehle en medewerkers, 2016-2020", + "templates.cliHint": "Download the CLI at https://github.com/squidex/squidex-samples to use the templates.", + "templates.reloaded": "Templates reloaded.", "tour.joinForum": "Word lid van ons forum", "tour.joinGithub": "Bezoek ons ​​op Github", "tour.skip": "Tour overslaan", diff --git a/backend/i18n/frontend_zh.json b/backend/i18n/frontend_zh.json index 1a66de1af..b3a135a8d 100644 --- a/backend/i18n/frontend_zh.json +++ b/backend/i18n/frontend_zh.json @@ -380,6 +380,7 @@ "common.tagAddSchema": ", 添加Schemas", "common.tags": "标签", "common.tagsAll": "所有标签", + "common.templates": "Templates", "common.time": "时间", "common.to": "To", "common.update": "更新", @@ -979,6 +980,8 @@ "start.loginHint": "登录按钮将打开一个新的弹出窗口。一旦您登录成功,我们会将您重定向到 Squidex 管理门户。", "start.madeBy": "自豪地制作", "start.madeByCopyright": "Sebastian Stehle 和贡献者,2016-2021", + "templates.cliHint": "Download the CLI at https://github.com/squidex/squidex-samples to use the templates.", + "templates.reloaded": "Templates reloaded.", "tour.joinForum": "加入我们的论坛", "tour.joinGithub": "加入我们的 Github", "tour.skip": "跳过游览", diff --git a/backend/i18n/source/frontend_en.json b/backend/i18n/source/frontend_en.json index 66d6463cb..e75dd5cfe 100644 --- a/backend/i18n/source/frontend_en.json +++ b/backend/i18n/source/frontend_en.json @@ -380,6 +380,7 @@ "common.tagAddSchema": ", to add schema", "common.tags": "Tags", "common.tagsAll": "All tags", + "common.templates": "Templates", "common.time": "Time", "common.to": "To", "common.update": "Update", @@ -979,6 +980,8 @@ "start.loginHint": "The login button will open a new popup. Once you are logged in successful we will redirect you to the Squidex management portal.", "start.madeBy": "Proudly made by", "start.madeByCopyright": "Sebastian Stehle and Contributors, 2016-2021", + "templates.cliHint": "Download the CLI at https://github.com/squidex/squidex-samples to use the templates.", + "templates.reloaded": "Templates reloaded.", "tour.joinForum": "Join our Forum", "tour.joinGithub": "Join us on Github", "tour.skip": "Skip Tour", diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/AlwaysCreateClientCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AlwaysCreateClientCommandMiddleware.cs similarity index 95% rename from backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/AlwaysCreateClientCommandMiddleware.cs rename to backend/src/Squidex.Domain.Apps.Entities/Apps/AlwaysCreateClientCommandMiddleware.cs index 97f8a5de7..2439e0554 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/AlwaysCreateClientCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AlwaysCreateClientCommandMiddleware.cs @@ -9,7 +9,7 @@ using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; -namespace Squidex.Domain.Apps.Entities.Apps.Templates +namespace Squidex.Domain.Apps.Entities.Apps { public sealed class AlwaysCreateClientCommandMiddleware : ICommandMiddleware { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs deleted file mode 100644 index 06ce93aa1..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs +++ /dev/null @@ -1,144 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; -using Squidex.Text; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class ArrayFieldBuilder : FieldBuilder - { - private UpsertSchemaField TypedField - { - get => (UpsertSchemaField)Field; - } - - public ArrayFieldBuilder(UpsertSchemaField field, ArrayFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - - public ArrayFieldBuilder AddAssets(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new AssetFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddBoolean(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new BooleanFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddDateTime(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new DateTimeFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddComponent(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new ComponentFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddComponents(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new ComponentsFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddJson(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new JsonFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddNumber(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new NumberFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddReferences(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new ReferencesFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddString(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new StringFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddTags(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new TagsFieldBuilder(field, properties, Schema)); - - return this; - } - - public ArrayFieldBuilder AddUI(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new UIFieldBuilder(field, properties, Schema)); - - return this; - } - - private (UpsertSchemaNestedField, T) AddField(string name) where T : FieldProperties, new() - { - var properties = new T - { - Label = name - }; - - var nestedField = new UpsertSchemaNestedField - { - Name = name.ToCamelCase(), - Properties = properties - }; - - TypedField.Nested ??= Array.Empty(); - TypedField.Nested = TypedField.Nested.Union(new[] { nestedField }).ToArray(); - - return (nestedField, properties); - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs deleted file mode 100644 index 47648668c..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class AssetFieldBuilder : FieldBuilder - { - public AssetFieldBuilder(UpsertSchemaFieldBase field, AssetsFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs deleted file mode 100644 index 1b3f93d02..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class BooleanFieldBuilder : FieldBuilder - { - public BooleanFieldBuilder(UpsertSchemaFieldBase field, BooleanFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs deleted file mode 100644 index 6704f03f0..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class ComponentFieldBuilder : FieldBuilder - { - public ComponentFieldBuilder(UpsertSchemaFieldBase field, ComponentFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs deleted file mode 100644 index 0d8a6581a..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class ComponentsFieldBuilder : FieldBuilder - { - public ComponentsFieldBuilder(UpsertSchemaFieldBase field, ComponentsFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs deleted file mode 100644 index 862f5964b..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class DateTimeFieldBuilder : FieldBuilder - { - public DateTimeFieldBuilder(UpsertSchemaFieldBase field, DateTimeFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs deleted file mode 100644 index 8100c5d5a..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs +++ /dev/null @@ -1,97 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core; -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public abstract class FieldBuilder - { - protected UpsertSchemaFieldBase Field { get; init; } - - protected CreateSchema Schema { get; init; } - } - - public abstract class FieldBuilder : FieldBuilder where T : FieldBuilder where TProperties : FieldProperties - { - private TProperties properties; - - protected FieldBuilder(UpsertSchemaFieldBase field, TProperties properties, CreateSchema schema) - { - this.properties = properties; - - Field = field; - Schema = schema; - } - - public T Localizable() - { - if (Field is UpsertSchemaField localizableField) - { - localizableField.Partitioning = Partitioning.Language.Key; - } - - return (T)(object)this; - } - - public T Disabled(bool isDisabled = true) - { - Field.IsDisabled = isDisabled; - - return (T)(object)this; - } - - public T Hidden(bool isHidden = true) - { - Field.IsHidden = isHidden; - - return (T)(object)this; - } - - public T Label(string? label) - { - return Properties(x => x with { Label = label }); - } - - public T Hints(string? hints) - { - return Properties(x => x with { Hints = hints }); - } - - public T Required(bool isRequired = true) - { - return Properties(x => x with { IsRequired = isRequired }); - } - - public T Properties(Func updater) - { - properties = updater(properties); - - Field.Properties = properties; - - return (T)(object)this; - } - - public T ShowInList() - { - Schema.FieldsInLists ??= new FieldNames(); - Schema.FieldsInLists.Add(Field.Name); - - return (T)(object)this; - } - - public T ShowInReferences() - { - Schema.FieldsInReferences ??= new FieldNames(); - Schema.FieldsInReferences.Add(Field.Name); - - return (T)(object)this; - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs deleted file mode 100644 index 7cd234bd2..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class JsonFieldBuilder : FieldBuilder - { - public JsonFieldBuilder(UpsertSchemaFieldBase field, JsonFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs deleted file mode 100644 index e4050488e..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class NumberFieldBuilder : FieldBuilder - { - public NumberFieldBuilder(UpsertSchemaFieldBase field, NumberFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs deleted file mode 100644 index 8241ec868..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class ReferencesFieldBuilder : FieldBuilder - { - public ReferencesFieldBuilder(UpsertSchemaFieldBase field, ReferencesFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs deleted file mode 100644 index e0764e894..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs +++ /dev/null @@ -1,203 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; -using Squidex.Text; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class SchemaBuilder - { - private readonly CreateSchema command; - - public SchemaBuilder(CreateSchema command) - { - this.command = command; - } - - public static SchemaBuilder Create(string name) - { - var schemaName = name.ToKebabCase(); - - return new SchemaBuilder(new CreateSchema - { - Name = schemaName - }).Published().WithLabel(name); - } - - public SchemaBuilder WithLabel(string? label) - { - if (command.Properties == null) - { - command.Properties = new SchemaProperties { Label = label }; - } - else - { - command.Properties = command.Properties with { Label = label }; - } - - return this; - } - - public SchemaBuilder WithScripts(SchemaScripts scripts) - { - command.Scripts = scripts; - - return this; - } - - public SchemaBuilder Published() - { - command.IsPublished = true; - - return this; - } - - public SchemaBuilder Singleton() - { - command.Type = SchemaType.Singleton; - - return this; - } - - public SchemaBuilder AddArray(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new ArrayFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddAssets(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new AssetFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddBoolean(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new BooleanFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddComponent(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new ComponentFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddComponents(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new ComponentsFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddDateTime(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new DateTimeFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddJson(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new JsonFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddNumber(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new NumberFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddReferences(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new ReferencesFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddString(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new StringFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddTags(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new TagsFieldBuilder(field, properties, command)); - - return this; - } - - public SchemaBuilder AddUI(string name, Action configure) - { - var (field, properties) = AddField(name); - - configure(new UIFieldBuilder(field, properties, command)); - - return this; - } - - private (UpsertSchemaField, T) AddField(string name) where T : FieldProperties, new() - { - var properties = new T { Label = name }; - - var field = new UpsertSchemaField - { - Name = name.ToCamelCase(), - Properties = properties, - }; - - if (command.Fields == null) - { - command.Fields = new[] { field }; - } - else - { - command.Fields = command.Fields.Union(Enumerable.Repeat(field, 1)).ToArray(); - } - - return (field, properties); - } - - public CreateSchema Build() - { - return command; - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs deleted file mode 100644 index e0a6ed222..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class StringFieldBuilder : FieldBuilder - { - public StringFieldBuilder(UpsertSchemaFieldBase field, StringFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs deleted file mode 100644 index 45db55305..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class TagsFieldBuilder : FieldBuilder - { - public TagsFieldBuilder(UpsertSchemaFieldBase field, TagsFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs deleted file mode 100644 index ca4be917a..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.Commands; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders -{ - public sealed class UIFieldBuilder : FieldBuilder - { - public UIFieldBuilder(UpsertSchemaFieldBase field, UIFieldProperties properties, CreateSchema schema) - : base(field, properties, schema) - { - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs deleted file mode 100644 index 086ab0a19..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs +++ /dev/null @@ -1,127 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; -using Squidex.Domain.Apps.Entities.Contents.Commands; -using Squidex.Infrastructure; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates -{ - public sealed class CreateBlog : ITemplate - { - public string Name { get; } = "blog"; - - public Task RunAsync(PublishTemplate publish) - { - return Task.WhenAll( - CreatePagesAsync(publish), - CreatePostsAsync(publish)); - } - - private static async Task CreatePostsAsync(PublishTemplate publish) - { - var postsId = await CreatePostsSchemaAsync(publish); - - await publish(new CreateContent - { - SchemaId = postsId, - Data = - new ContentData() - .AddField("title", - new ContentFieldData() - .AddInvariant("My first post with Squidex")) - .AddField("text", - new ContentFieldData() - .AddInvariant("Just created a blog with Squidex. I love it!")), - Status = Status.Published - }); - } - - private static async Task CreatePagesAsync(PublishTemplate publish) - { - var pagesId = await CreatePagesSchemaAsync(publish); - - await publish(new CreateContent - { - SchemaId = pagesId, - Data = - new ContentData() - .AddField("title", - new ContentFieldData() - .AddInvariant("About Me")) - .AddField("text", - new ContentFieldData() - .AddInvariant("I love Squidex and SciFi!")), - Status = Status.Published - }); - } - - private static async Task> CreatePostsSchemaAsync(PublishTemplate publish) - { - var schema = - SchemaBuilder.Create("Posts") - .AddString("Title", f => f - .Properties(p => p with - { - MaxLength = 100 - }) - .Required() - .ShowInList() - .Hints("The title of the post.")) - .AddString("Text", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.RichText - }) - .Required() - .Hints("The text of the post.")) - .AddString("Slug", f => f - .Disabled() - .Label("Slug (Autogenerated)") - .Hints("Autogenerated slug that can be used to identity the post.")) - .WithScripts(DefaultScripts.GenerateSlug) - .Build(); - - await publish(schema); - - return NamedId.Of(schema.SchemaId, schema.Name); - } - - private static async Task> CreatePagesSchemaAsync(PublishTemplate publish) - { - var schema = - SchemaBuilder.Create("Pages") - .AddString("Title", f => f - .Properties(p => p with - { - MaxLength = 100 - }) - .Required() - .ShowInList() - .Hints("The title of the page.")) - .AddString("Text", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.RichText - }) - .Required() - .Hints("The text of the page.")) - .AddString("Slug", f => f - .Disabled() - .Label("Slug (Autogenerated)") - .Hints("Autogenerated slug that can be used to identity the page.")) - .WithScripts(DefaultScripts.GenerateSlug) - .Build(); - - await publish(schema); - - return NamedId.Of(schema.SchemaId, schema.Name); - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs deleted file mode 100644 index e05e21e94..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs +++ /dev/null @@ -1,269 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Assets; -using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; -using Squidex.Domain.Apps.Entities.Contents.Commands; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Collections; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates -{ - public sealed class CreateProfile : ITemplate - { - public string Name { get; } = "profile"; - - public Task RunAsync(PublishTemplate publish) - { - return Task.WhenAll( - CreateBasicsAsync(publish), - CreateEducationSchemaAsync(publish), - CreateExperienceSchemaAsync(publish), - CreateProjectsSchemaAsync(publish), - CreatePublicationsSchemaAsync(publish), - CreateSkillsSchemaAsync(publish)); - } - - private static async Task CreateBasicsAsync(PublishTemplate publish) - { - var postsId = await CreateBasicsSchemaAsync(publish); - - await publish(new UpdateContent - { - ContentId = postsId.Id, - Data = - new ContentData() - .AddField("firstName", - new ContentFieldData() - .AddInvariant("John")) - .AddField("lastName", - new ContentFieldData() - .AddInvariant("Doe")) - .AddField("profession", - new ContentFieldData() - .AddInvariant("Software Developer")), - SchemaId = postsId - }); - } - - private static async Task> CreateBasicsSchemaAsync(PublishTemplate publish) - { - var command = - SchemaBuilder.Create("Basics") - .Singleton() - .AddString("First Name", f => f - .Required() - .ShowInList() - .Hints("Your first name.")) - .AddString("Last Name", f => f - .Required() - .ShowInList() - .Hints("Your last name.")) - .AddAssets("Image", f => f - .Properties(p => p with - { - ExpectedType = AssetType.Image, - MaxItems = 1, - MinItems = 1 - }) - .Hints("Your profile image.")) - .AddString("Profession", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.TextArea - }) - .Required() - .Hints("Describe your profession.")) - .AddString("Summary", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.TextArea - }) - .Hints("Write a short summary about yourself.")) - .AddString("Legal Terms", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.TextArea - }) - .Hints("The terms to fulfill legal requirements.")) - .AddString("Github Link", f => f - .Hints("An optional link to your Github account.")) - .AddString("Blog Link", f => f - .Hints("An optional link to your Blog.")) - .AddString("Twitter Link", f => f - .Hints("An optional link to your Twitter account.")) - .AddString("LinkedIn Link", f => f - .Hints("An optional link to your LinkedIn account.")) - .AddString("Email Address", f => f - .Hints("An optional email address to contact you.")) - .Build(); - - await publish(command); - - return NamedId.Of(command.SchemaId, command.Name); - } - - private static async Task> CreateProjectsSchemaAsync(PublishTemplate publish) - { - var schema = - SchemaBuilder.Create("Projects") - .AddString("Name", f => f - .Required() - .ShowInList() - .Hints("The name of your project.")) - .AddString("Description", f => f - .Properties(p => p with - { - Editor = StringFieldEditor.TextArea - }) - .Required() - .Hints("Describe your project.")) - .AddAssets("Image", f => f - .Properties(p => p with - { - ExpectedType = AssetType.Image, - MaxItems = 1, - MinItems = 1 - }) - .Required() - .Hints("An image or screenshot for your project.")) - .AddString("Label", f => f - .Properties(p => p with { Editor = StringFieldEditor.TextArea }) - .Hints("An optional label to categorize your project, e.g. 'Open Source'.")) - .AddString("Link", f => f - .Hints("An optional link to your project.")) - .AddNumber("Year", f => f - .Hints("The year, when you realized the project, used for sorting only.")) - .Build(); - - await publish(schema); - - return NamedId.Of(schema.SchemaId, schema.Name); - } - - private static async Task> CreateExperienceSchemaAsync(PublishTemplate publish) - { - var schema = - SchemaBuilder.Create("Experience") - .AddString("Position", f => f - .Required() - .ShowInList() - .Hints("Your position in this job.")) - .AddString("Company", f => f - .Required() - .ShowInList() - .Hints("The company or organization you worked for.")) - .AddAssets("Logo", f => f - .Properties(p => p with - { - ExpectedType = AssetType.Image, - MaxItems = 1, - MinItems = 1 - }) - .Hints("The logo of the company or organization you worked for.")) - .AddDateTime("From", f => f - .Required() - .Hints("The start date.")) - .AddDateTime("To", f => f - .Hints("The end date, keep empty if you still work there.")) - .Build(); - - await publish(schema); - - return NamedId.Of(schema.SchemaId, schema.Name); - } - - private static async Task> CreateEducationSchemaAsync(PublishTemplate publish) - { - var schema = - SchemaBuilder.Create("Education") - .AddString("Degree", f => f - .Required() - .ShowInList() - .Hints("The degree you got or achieved.")) - .AddString("School", f => f - .Required() - .ShowInList() - .Hints("The school or university.")) - .AddAssets("Logo", f => f - .Properties(p => p with - { - ExpectedType = AssetType.Image, - MaxItems = 1, - MinItems = 1 - }) - .Hints("The logo of the school or university.")) - .AddDateTime("From", f => f - .Required() - .Hints("The start date.")) - .AddDateTime("To", f => f - .Hints("The end date, keep empty if you still study there.")) - .Build(); - - await publish(schema); - - return NamedId.Of(schema.SchemaId, schema.Name); - } - - private static async Task> CreatePublicationsSchemaAsync(PublishTemplate publish) - { - var command = - SchemaBuilder.Create("Publications") - .AddString("Name", f => f - .Required() - .ShowInList() - .Hints("The name or title of your publication.")) - .AddAssets("Cover", f => f - .Properties(p => p with - { - ExpectedType = AssetType.Image, - MaxItems = 1, - MinItems = 1 - }) - .Hints("The cover of your publication.")) - .AddString("Description", f => f - .Hints("Describe the content of your publication.")) - .AddString("Link", f => f - .Hints("Optional link to your publication.")) - .Build(); - - await publish(command); - - return NamedId.Of(command.SchemaId, command.Name); - } - - private static async Task> CreateSkillsSchemaAsync(PublishTemplate publish) - { - var command = - SchemaBuilder.Create("Skills") - .AddString("Name", f => f - .Required() - .ShowInList() - .Hints("The name of the skill.")) - .AddString("Experience", f => f - .Properties(p => p with - { - AllowedValues = ReadonlyList.Create( - "Beginner", - "Advanced", - "Professional", - "Expert"), - Editor = StringFieldEditor.Dropdown, - }) - .Required() - .ShowInList() - .Hints("The level of experience.")) - .Build(); - - await publish(command); - - return NamedId.Of(command.SchemaId, command.Name); - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs deleted file mode 100644 index e4d86e7f2..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Core.Schemas; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates -{ - public static class DefaultScripts - { - private const string ScriptToGenerateSlug = @" - var data = ctx.data; - - if (data.title && data.title.iv) { - data.slug = { iv: slugify(data.title.iv) }; - - replace(data); - }"; - - public static readonly SchemaScripts GenerateSlug = new SchemaScripts - { - Create = ScriptToGenerateSlug, - Update = ScriptToGenerateSlug - }; - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/ITemplate.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Template.cs similarity index 72% rename from backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/ITemplate.cs rename to backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Template.cs index 4ed946563..1016fe07a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/ITemplate.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Template.cs @@ -5,12 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Entities.Apps.Templates { - public interface ITemplate + public sealed record Template(string Name, string Title, string Description) { - string Name { get; } - - Task RunAsync(PublishTemplate publish); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs deleted file mode 100644 index 59a6904f0..000000000 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs +++ /dev/null @@ -1,49 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Domain.Apps.Entities.Apps.Commands; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; - -#pragma warning disable MA0048 // File name must match type name - -namespace Squidex.Domain.Apps.Entities.Apps.Templates -{ - public delegate Task PublishTemplate(IAppCommand command); - - public sealed class TemplateCommandMiddleware : ICommandMiddleware - { - private readonly Dictionary templates; - - public TemplateCommandMiddleware(IEnumerable templates) - { - this.templates = templates.ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); - } - - public async Task HandleAsync(CommandContext context, NextDelegate next) - { - if (context.IsCompleted && context.Command is CreateApp createApp && !string.IsNullOrWhiteSpace(createApp.Template)) - { - if (templates.TryGetValue(createApp.Template, out var template)) - { - var appId = NamedId.Of(createApp.AppId, createApp.Name); - - var publish = new PublishTemplate(command => - { - command.AppId = appId; - - return context.CommandBus.PublishAsync(command); - }); - - await template.RunAsync(publish); - } - } - - await next(context); - } - } -} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplatesClient.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplatesClient.cs new file mode 100644 index 000000000..a37c30657 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplatesClient.cs @@ -0,0 +1,69 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Net; +using System.Text.RegularExpressions; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Apps.Templates +{ + public sealed class TemplatesClient + { + private const string DetailUrl = "https://raw.githubusercontent.com/Squidex/templates/main"; + private const string OverviewUrl = "https://raw.githubusercontent.com/Squidex/templates/main/README.md"; + private static readonly Regex Regex = new Regex("\\* \\[(?.*)\\]\\((?<Name>.*)\\/README\\.md\\): (?<Description>.*)", RegexOptions.Compiled | RegexOptions.ExplicitCapture); + private readonly IHttpClientFactory httpClientFactory; + + public TemplatesClient(IHttpClientFactory httpClientFactory) + { + this.httpClientFactory = httpClientFactory; + } + + public async Task<List<Template>> GetTemplatesAsync( + CancellationToken ct = default) + { + using (var httpClient = httpClientFactory.CreateClient()) + { + var url = OverviewUrl; + + var text = await httpClient.GetStringAsync(url, ct); + + var result = new List<Template>(); + + foreach (Match match in Regex.Matches(text)) + { + result.Add(new Template( + match.Groups["Name"].Value, + match.Groups["Title"].Value, + match.Groups["Description"].Value)); + } + + return result; + } + } + + public async Task<string?> GetDetailAsync(string name, + CancellationToken ct = default) + { + Guard.NotNullOrEmpty(name); + + using (var httpClient = httpClientFactory.CreateClient()) + { + var url = $"{DetailUrl}/{name}/README.md"; + + var response = await httpClient.GetAsync(url, ct); + + if (response.StatusCode == HttpStatusCode.NotFound) + { + return null; + } + + return await response.Content.ReadAsStringAsync(ct); + } + } + } +} diff --git a/backend/src/Squidex.Web/Resource.cs b/backend/src/Squidex.Web/Resource.cs index 1d247bfe9..375ac2303 100644 --- a/backend/src/Squidex.Web/Resource.cs +++ b/backend/src/Squidex.Web/Resource.cs @@ -19,37 +19,37 @@ namespace Squidex.Web [JsonProperty("_links")] public Dictionary<string, ResourceLink> Links { get; } = new Dictionary<string, ResourceLink>(); - public void AddSelfLink(string href) + protected void AddSelfLink(string href) { AddGetLink("self", href); } - public void AddGetLink(string rel, string href, string? metadata = null) + protected void AddGetLink(string rel, string href, string? metadata = null) { AddLink(rel, "GET", href, metadata); } - public void AddPatchLink(string rel, string href, string? metadata = null) + protected void AddPatchLink(string rel, string href, string? metadata = null) { AddLink(rel, "PATCH", href, metadata); } - public void AddPostLink(string rel, string href, string? metadata = null) + protected void AddPostLink(string rel, string href, string? metadata = null) { AddLink(rel, "POST", href, metadata); } - public void AddPutLink(string rel, string href, string? metadata = null) + protected void AddPutLink(string rel, string href, string? metadata = null) { AddLink(rel, "PUT", href, metadata); } - public void AddDeleteLink(string rel, string href, string? metadata = null) + protected void AddDeleteLink(string rel, string href, string? metadata = null) { AddLink(rel, "DELETE", href, metadata); } - public void AddLink(string rel, string method, string href, string? metadata = null) + protected void AddLink(string rel, string method, string href, string? metadata = null) { Guard.NotNullOrEmpty(rel); Guard.NotNullOrEmpty(href); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppAssetsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppAssetsController.cs index 79e854ba9..fa3a109e3 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppAssetsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppAssetsController.cs @@ -82,7 +82,7 @@ namespace Squidex.Areas.Api.Controllers.Apps private AssetScriptsDto GetResponse(IAppEntity result) { - return AssetScriptsDto.FromApp(result, Resources); + return AssetScriptsDto.FromDomain(result, Resources); } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs index f4ef28c6c..41e50c533 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs @@ -138,7 +138,7 @@ namespace Squidex.Areas.Api.Controllers.Apps private AppLanguagesDto GetResponse(IAppEntity result) { - return AppLanguagesDto.FromApp(result, Resources); + return AppLanguagesDto.FromDomain(result, Resources); } private static Language ParseLanguage(string language) diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs index 0e740a3e6..46d9b30f0 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs @@ -168,7 +168,7 @@ namespace Squidex.Areas.Api.Controllers.Apps private RolesDto GetResponse(IAppEntity result) { - return RolesDto.FromApp(result, Resources); + return RolesDto.FromDomain(result, Resources); } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppSettingsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppSettingsController.cs index ebcf77d5f..25643e64d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppSettingsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppSettingsController.cs @@ -82,7 +82,7 @@ namespace Squidex.Areas.Api.Controllers.Apps private AppSettingsDto GetResponse(IAppEntity result) { - return AppSettingsDto.FromApp(result, Resources); + return AppSettingsDto.FromDomain(result, Resources); } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs index a5b0713f8..cca7e643e 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs @@ -60,7 +60,7 @@ namespace Squidex.Areas.Api.Controllers.Apps { var isFrontend = HttpContext.User.IsInClient(DefaultClients.Frontend); - return apps.OrderBy(x => x.Name).Select(a => AppDto.FromApp(a, userOrClientId, isFrontend, Resources)).ToArray(); + return apps.OrderBy(x => x.Name).Select(a => AppDto.FromDomain(a, userOrClientId, isFrontend, Resources)).ToArray(); }); Response.Headers[HeaderNames.ETag] = apps.ToEtag(); @@ -89,7 +89,7 @@ namespace Squidex.Areas.Api.Controllers.Apps var isFrontend = HttpContext.User.IsInClient(DefaultClients.Frontend); - return AppDto.FromApp(App, userOrClientId, isFrontend, Resources); + return AppDto.FromDomain(App, userOrClientId, isFrontend, Resources); }); Response.Headers[HeaderNames.ETag] = App.ToEtag(); @@ -213,7 +213,7 @@ namespace Squidex.Areas.Api.Controllers.Apps var isFrontend = HttpContext.User.IsInClient(DefaultClients.Frontend); - return AppDto.FromApp(x, userOrClientId, isFrontend, Resources); + return AppDto.FromDomain(x, userOrClientId, isFrontend, Resources); }); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs index c3321a22b..e4cbc2c40 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs @@ -92,7 +92,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models [LocalizedRequired] public JsonObject RoleProperties { get; set; } = EmptyObject; - public static AppDto FromApp(IAppEntity app, string userId, bool isFrontend, Resources resources) + public static AppDto FromDomain(IAppEntity app, string userId, bool isFrontend, Resources resources) { var result = SimpleMapper.Map(app, new AppDto()); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguageDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguageDto.cs index 714b6d20f..dfe0a5629 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguageDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguageDto.cs @@ -43,7 +43,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// </summary> public bool IsOptional { get; set; } - public static AppLanguageDto FromLanguage(Language language, LanguageConfig config, LanguagesConfig languages) + public static AppLanguageDto FromDomain(Language language, LanguageConfig config, LanguagesConfig languages) { var result = new AppLanguageDto { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguagesDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguagesDto.cs index 1b4380c80..3449a7c1c 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguagesDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguagesDto.cs @@ -19,14 +19,14 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models [LocalizedRequired] public AppLanguageDto[] Items { get; set; } - public static AppLanguagesDto FromApp(IAppEntity app, Resources resources) + public static AppLanguagesDto FromDomain(IAppEntity app, Resources resources) { var config = app.Languages; var result = new AppLanguagesDto { Items = config.Languages - .Select(x => AppLanguageDto.FromLanguage(x.Key, x.Value, config)) + .Select(x => AppLanguageDto.FromDomain(x.Key, x.Value, config)) .Select(x => x.CreateLinks(resources, app)) .OrderByDescending(x => x.IsMaster).ThenBy(x => x.Iso2Code) .ToArray() diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppSettingsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppSettingsDto.cs index db73b07bd..07f624a38 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppSettingsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppSettingsDto.cs @@ -40,13 +40,13 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// </summary> public long Version { get; set; } - public static AppSettingsDto FromApp(IAppEntity app, Resources resources) + public static AppSettingsDto FromDomain(IAppEntity app, Resources resources) { var settings = app.Settings; var result = new AppSettingsDto { - Editors = settings.Editors.Select(EditorDto.FromEditor).ToArray(), + Editors = settings.Editors.Select(EditorDto.FromDomain).ToArray(), HideDateTimeModeButton = settings.HideDateTimeModeButton, HideScheduler = settings.HideScheduler, Patterns = settings.Patterns.Select(PatternDto.FromPattern).ToArray(), diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs index 2c50c7637..d1982b276 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs @@ -43,7 +43,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// </summary> public long Version { get; set; } - public static AssetScriptsDto FromApp(IAppEntity app, Resources resources) + public static AssetScriptsDto FromDomain(IAppEntity app, Resources resources) { var result = SimpleMapper.Map(app.AssetScripts, new AssetScriptsDto()); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs index 12b2d91ef..bbeec1d62 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs @@ -38,7 +38,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// </summary> public string? Role { get; set; } - public static ContributorDto FromIdAndRole(string id, string role) + public static ContributorDto FromDomain(string id, string role) { var result = new ContributorDto { ContributorId = id, Role = role }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs index 7a6637cbd..0152b36e4 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs @@ -40,7 +40,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models var result = new ContributorsDto { Items = app.Contributors - .Select(x => ContributorDto.FromIdAndRole(x.Key, x.Value)) + .Select(x => ContributorDto.FromDomain(x.Key, x.Value)) .Select(x => x.CreateUser(users)) .Select(x => x.CreateLinks(resources)) .OrderBy(x => x.ContributorName) diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateAppDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateAppDto.cs index 4a8b18ab4..71860dfdf 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateAppDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateAppDto.cs @@ -20,11 +20,6 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models [LocalizedRegularExpression("^[a-z0-9]+(\\-[a-z0-9]+)*$")] public string Name { get; set; } - /// <summary> - /// Initialize the app with the inbuilt template. - /// </summary> - public string? Template { get; set; } - public CreateApp ToCommand() { return SimpleMapper.Map(this, new CreateApp()); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/EditorDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/EditorDto.cs index b71afadf1..8f38d94fd 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/EditorDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/EditorDto.cs @@ -25,9 +25,11 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models [LocalizedRequired] public string Url { get; set; } - public static EditorDto FromEditor(Editor editor) + public static EditorDto FromDomain(Editor editor) { - return SimpleMapper.Map(editor, new EditorDto()); + var result = SimpleMapper.Map(editor, new EditorDto()); + + return result; } public Editor ToEditor() diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs index 9fe771551..015de04ee 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs @@ -32,7 +32,9 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models public static PatternDto FromPattern(Pattern pattern) { - return SimpleMapper.Map(pattern, new PatternDto()); + var result = SimpleMapper.Map(pattern, new PatternDto()); + + return result; } public Pattern ToPattern() diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RoleDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RoleDto.cs index bb21cd804..f8a37c3d7 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RoleDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RoleDto.cs @@ -48,7 +48,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models [LocalizedRequired] public JsonObject Properties { get; set; } - public static RoleDto FromRole(Role role, IAppEntity app) + public static RoleDto FromDomain(Role role, IAppEntity app) { var result = new RoleDto { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RolesDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RolesDto.cs index a69d9a0c1..d5ddc766e 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RolesDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RolesDto.cs @@ -19,13 +19,13 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models [LocalizedRequired] public RoleDto[] Items { get; set; } - public static RolesDto FromApp(IAppEntity app, Resources resources) + public static RolesDto FromDomain(IAppEntity app, Resources resources) { var result = new RolesDto { Items = app.Roles.All - .Select(x => RoleDto.FromRole(x, app)) + .Select(x => RoleDto.FromDomain(x, app)) .Select(x => x.CreateLinks(resources)) .OrderBy(x => x.Name) .ToArray() diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs index b6b7d0aed..45a17dc7c 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs @@ -42,13 +42,13 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// </summary> public Status Initial { get; set; } - public static WorkflowDto FromWorkflow(DomainId id, Workflow workflow) + public static WorkflowDto FromDomain(DomainId id, Workflow workflow) { var result = SimpleMapper.Map(workflow, new WorkflowDto { Steps = workflow.Steps.ToDictionary( x => x.Key, - x => WorkflowStepDto.FromWorkflowStep(x.Value)), + x => WorkflowStepDto.FromDomain(x.Value)), Id = id }); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs index 902afb5d5..dd6cd3ef1 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs @@ -41,23 +41,23 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// </summary> public string[]? NoUpdateRoles { get; set; } - public static WorkflowStepDto FromWorkflowStep(WorkflowStep step) + public static WorkflowStepDto FromDomain(WorkflowStep step) { - var response = SimpleMapper.Map(step, new WorkflowStepDto + var result = SimpleMapper.Map(step, new WorkflowStepDto { Transitions = step.Transitions.ToDictionary( y => y.Key, - y => WorkflowTransitionDto.FromWorkflowTransition(y.Value)) + y => WorkflowTransitionDto.FromDomain(y.Value)) }); if (step.NoUpdate != null) { - response.NoUpdate = true; - response.NoUpdateExpression = step.NoUpdate.Expression; - response.NoUpdateRoles = step.NoUpdate.Roles?.ToArray(); + result.NoUpdate = true; + result.NoUpdateExpression = step.NoUpdate.Expression; + result.NoUpdateRoles = step.NoUpdate.Roles?.ToArray(); } - return response; + return result; } public WorkflowStep ToWorkflowStep() diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowTransitionDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowTransitionDto.cs index c3c61384e..b30781d84 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowTransitionDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowTransitionDto.cs @@ -21,9 +21,11 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models /// </summary> public string[]? Roles { get; set; } - public static WorkflowTransitionDto FromWorkflowTransition(WorkflowTransition transition) + public static WorkflowTransitionDto FromDomain(WorkflowTransition transition) { - return new WorkflowTransitionDto { Expression = transition.Expression, Roles = transition.Roles?.ToArray() }; + var result = new WorkflowTransitionDto { Expression = transition.Expression, Roles = transition.Roles?.ToArray() }; + + return result; } public WorkflowTransition ToWorkflowTransition() diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowsDto.cs index d7888ff02..cc7c1f5f3 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowsDto.cs @@ -32,7 +32,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models { Items = app.Workflows - .Select(x => WorkflowDto.FromWorkflow(x.Key, x.Value)) + .Select(x => WorkflowDto.FromDomain(x.Key, x.Value)) .Select(x => x.CreateLinks(resources)) .ToArray() }; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs index 69942014e..c3c6bdbfa 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs @@ -59,7 +59,7 @@ namespace Squidex.Areas.Api.Controllers.Assets var response = Deferred.Response(() => { - return AssetFoldersDto.FromAssets(folders, path, Resources); + return AssetFoldersDto.FromDomain(folders, path, Resources); }); Response.Headers[HeaderNames.ETag] = folders.ToEtag(); @@ -168,7 +168,7 @@ namespace Squidex.Areas.Api.Controllers.Assets { var context = await CommandBus.PublishAsync(command); - return AssetFolderDto.FromAssetFolder(context.Result<IAssetFolderEntity>(), Resources); + return AssetFolderDto.FromDomain(context.Result<IAssetFolderEntity>(), Resources); } private Task<IReadOnlyList<IAssetFolderEntity>> GetAssetPathAsync(DomainId parentId, AssetFolderScope scope) diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs index a01d0c0c3..ad2eda78d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs @@ -126,7 +126,7 @@ namespace Squidex.Areas.Api.Controllers.Assets var response = Deferred.Response(() => { - return AssetsDto.FromAssets(assets, Resources); + return AssetsDto.FromDomain(assets, Resources); }); return Ok(response); @@ -155,7 +155,7 @@ namespace Squidex.Areas.Api.Controllers.Assets var response = Deferred.Response(() => { - return AssetsDto.FromAssets(assets, Resources); + return AssetsDto.FromDomain(assets, Resources); }); return Ok(response); @@ -186,7 +186,7 @@ namespace Squidex.Areas.Api.Controllers.Assets var response = Deferred.Response(() => { - return AssetDto.FromAsset(asset, Resources); + return AssetDto.FromDomain(asset, Resources); }); return Ok(response); @@ -280,7 +280,7 @@ namespace Squidex.Areas.Api.Controllers.Assets var context = await CommandBus.PublishAsync(command); var result = context.Result<BulkUpdateResult>(); - var response = result.Select(x => BulkResultDto.FromBulkResult(x, HttpContext)).ToArray(); + var response = result.Select(x => BulkResultDto.FromDomain(x, HttpContext)).ToArray(); return Ok(response); } @@ -452,11 +452,11 @@ namespace Squidex.Areas.Api.Controllers.Assets if (context.PlainResult is AssetDuplicate created) { - return AssetDto.FromAsset(created.Asset, Resources, true); + return AssetDto.FromDomain(created.Asset, Resources, true); } else { - return AssetDto.FromAsset(context.Result<IEnrichedAssetEntity>(), Resources); + return AssetDto.FromDomain(context.Result<IEnrichedAssetEntity>(), Resources); } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs index efb59595e..fc4f43876 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs @@ -160,68 +160,68 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models get => Metadata.GetPixelHeight(); } - public static AssetDto FromAsset(IEnrichedAssetEntity asset, Resources resources, bool isDuplicate = false) + public static AssetDto FromDomain(IEnrichedAssetEntity asset, Resources resources, bool isDuplicate = false) { - var response = SimpleMapper.Map(asset, new AssetDto()); + var result = SimpleMapper.Map(asset, new AssetDto()); - response.Tags = asset.TagNames; - - response.FileType = asset.FileName.FileType(); + result.Tags = asset.TagNames; if (isDuplicate) { - response.Meta = new AssetMeta + result.Meta = new AssetMeta { IsDuplicate = "true" }; } - return CreateLinks(response, resources); + result.FileType = asset.FileName.FileType(); + + return result.CreateLinks(resources); } - private static AssetDto CreateLinks(AssetDto response, Resources resources) + private AssetDto CreateLinks(Resources resources) { var app = resources.App; - var values = new { app, id = response.Id }; + var values = new { app, id = Id }; - response.AddSelfLink(resources.Url<AssetsController>(x => nameof(x.GetAsset), values)); + AddSelfLink(resources.Url<AssetsController>(x => nameof(x.GetAsset), values)); if (resources.CanUpdateAsset) { - response.AddPutLink("update", resources.Url<AssetsController>(x => nameof(x.PutAsset), values)); + AddPutLink("update", resources.Url<AssetsController>(x => nameof(x.PutAsset), values)); - response.AddPutLink("move", resources.Url<AssetsController>(x => nameof(x.PutAssetParent), values)); + AddPutLink("move", resources.Url<AssetsController>(x => nameof(x.PutAssetParent), values)); } if (resources.CanUploadAsset) { - response.AddPutLink("upload", resources.Url<AssetsController>(x => nameof(x.PutAssetContent), values)); + AddPutLink("upload", resources.Url<AssetsController>(x => nameof(x.PutAssetContent), values)); } if (resources.CanDeleteAsset) { - response.AddDeleteLink("delete", resources.Url<AssetsController>(x => nameof(x.DeleteAsset), values)); + AddDeleteLink("delete", resources.Url<AssetsController>(x => nameof(x.DeleteAsset), values)); } - if (!string.IsNullOrWhiteSpace(response.Slug)) + if (!string.IsNullOrWhiteSpace(Slug)) { - var idValues = new { app, idOrSlug = response.Id, more = response.Slug }; + var idValues = new { app, idOrSlug = Id, more = Slug }; - response.AddGetLink("content", resources.Url<AssetContentController>(x => nameof(x.GetAssetContentBySlug), idValues)); + AddGetLink("content", resources.Url<AssetContentController>(x => nameof(x.GetAssetContentBySlug), idValues)); - var slugValues = new { app, idOrSlug = response.Slug }; + var slugValues = new { app, idOrSlug = Slug }; - response.AddGetLink("content/slug", resources.Url<AssetContentController>(x => nameof(x.GetAssetContentBySlug), slugValues)); + AddGetLink("content/slug", resources.Url<AssetContentController>(x => nameof(x.GetAssetContentBySlug), slugValues)); } else { - var idValues = new { app, idOrSlug = response.Id }; + var idValues = new { app, idOrSlug = Id }; - response.AddGetLink("content", resources.Url<AssetContentController>(x => nameof(x.GetAssetContentBySlug), idValues)); + AddGetLink("content", resources.Url<AssetContentController>(x => nameof(x.GetAssetContentBySlug), idValues)); } - return response; + return this; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs index cb25ab359..62dba07da 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs @@ -36,30 +36,30 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models /// </summary> public long Version { get; set; } - public static AssetFolderDto FromAssetFolder(IAssetFolderEntity asset, Resources resources) + public static AssetFolderDto FromDomain(IAssetFolderEntity asset, Resources resources) { - var response = SimpleMapper.Map(asset, new AssetFolderDto()); + var result = SimpleMapper.Map(asset, new AssetFolderDto()); - return CreateLinks(response, resources); + return result.CreateLinks(resources); } - private static AssetFolderDto CreateLinks(AssetFolderDto response, Resources resources) + private AssetFolderDto CreateLinks(Resources resources) { - var values = new { app = resources.App, id = response.Id }; + var values = new { app = resources.App, id = Id }; if (resources.CanUpdateAsset) { - response.AddPutLink("update", resources.Url<AssetFoldersController>(x => nameof(x.PutAssetFolder), values)); + AddPutLink("update", resources.Url<AssetFoldersController>(x => nameof(x.PutAssetFolder), values)); - response.AddPutLink("move", resources.Url<AssetFoldersController>(x => nameof(x.PutAssetFolderParent), values)); + AddPutLink("move", resources.Url<AssetFoldersController>(x => nameof(x.PutAssetFolderParent), values)); } if (resources.CanUpdateAsset) { - response.AddDeleteLink("delete", resources.Url<AssetFoldersController>(x => nameof(x.DeleteAssetFolder), values)); + AddDeleteLink("delete", resources.Url<AssetFoldersController>(x => nameof(x.DeleteAssetFolder), values)); } - return response; + return this; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs index a16928429..85544b5af 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs @@ -31,31 +31,31 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models [LocalizedRequired] public AssetFolderDto[] Path { get; set; } - public static AssetFoldersDto FromAssets(IResultList<IAssetFolderEntity> assetFolders, IEnumerable<IAssetFolderEntity> path, Resources resources) + public static AssetFoldersDto FromDomain(IResultList<IAssetFolderEntity> assetFolders, IEnumerable<IAssetFolderEntity> path, Resources resources) { - var response = new AssetFoldersDto + var result = new AssetFoldersDto { Total = assetFolders.Total, - Items = assetFolders.Select(x => AssetFolderDto.FromAssetFolder(x, resources)).ToArray() + Items = assetFolders.Select(x => AssetFolderDto.FromDomain(x, resources)).ToArray() }; - response.Path = path.Select(x => AssetFolderDto.FromAssetFolder(x, resources)).ToArray(); + result.Path = path.Select(x => AssetFolderDto.FromDomain(x, resources)).ToArray(); - return CreateLinks(response, resources); + return result.CreateLinks(resources); } - private static AssetFoldersDto CreateLinks(AssetFoldersDto response, Resources resources) + private AssetFoldersDto CreateLinks(Resources resources) { var values = new { app = resources.App }; - response.AddSelfLink(resources.Url<AssetFoldersController>(x => nameof(x.GetAssetFolders), values)); + AddSelfLink(resources.Url<AssetFoldersController>(x => nameof(x.GetAssetFolders), values)); if (resources.CanUpdateAsset) { - response.AddPostLink("create", resources.Url<AssetFoldersController>(x => nameof(x.PostAssetFolder), values)); + AddPostLink("create", resources.Url<AssetFoldersController>(x => nameof(x.PostAssetFolder), values)); } - return response; + return this; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs index 89ac621c0..3f5e9d96c 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs @@ -25,38 +25,38 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models [LocalizedRequired] public AssetDto[] Items { get; set; } - public static AssetsDto FromAssets(IResultList<IEnrichedAssetEntity> assets, Resources resources) + public static AssetsDto FromDomain(IResultList<IEnrichedAssetEntity> assets, Resources resources) { - var response = new AssetsDto + var result = new AssetsDto { Total = assets.Total, - Items = assets.Select(x => AssetDto.FromAsset(x, resources)).ToArray() + Items = assets.Select(x => AssetDto.FromDomain(x, resources)).ToArray() }; - return CreateLinks(response, resources); + return result.CreateLinks(resources); } - private static AssetsDto CreateLinks(AssetsDto response, Resources resources) + private AssetsDto CreateLinks(Resources resources) { var values = new { app = resources.App }; - response.AddSelfLink(resources.Url<AssetsController>(x => nameof(x.GetAssets), values)); + AddSelfLink(resources.Url<AssetsController>(x => nameof(x.GetAssets), values)); if (resources.CanCreateAsset) { - response.AddPostLink("create", resources.Url<AssetsController>(x => nameof(x.PostAsset), values)); + AddPostLink("create", resources.Url<AssetsController>(x => nameof(x.PostAsset), values)); } if (resources.CanUpdateAsset) { var tagValue = new { values.app, name = "tag" }; - response.AddPutLink("tags/rename", resources.Url<AssetsController>(x => nameof(x.PutTag), tagValue)); + AddPutLink("tags/rename", resources.Url<AssetsController>(x => nameof(x.PutTag), tagValue)); } - response.AddGetLink("tags", resources.Url<AssetsController>(x => nameof(x.GetTags), values)); + AddGetLink("tags", resources.Url<AssetsController>(x => nameof(x.GetTags), values)); - return response; + return this; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs index da346e256..611bb939d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs @@ -48,7 +48,7 @@ namespace Squidex.Areas.Api.Controllers.Backups { var jobs = await backupService.GetBackupsAsync(AppId, HttpContext.RequestAborted); - var response = BackupJobsDto.FromBackups(jobs, Resources); + var response = BackupJobsDto.FromDomain(jobs, Resources); return Ok(response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs index df50f3b3b..b961244a0 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs @@ -45,7 +45,7 @@ namespace Squidex.Areas.Api.Controllers.Backups.Models /// </summary> public JobStatus Status { get; set; } - public static BackupJobDto FromBackup(IBackupJob backup, Resources resources) + public static BackupJobDto FromDomain(IBackupJob backup, Resources resources) { var result = SimpleMapper.Map(backup, new BackupJobDto()); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobsDto.cs index 15bac6bd1..5019b45ff 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobsDto.cs @@ -19,11 +19,11 @@ namespace Squidex.Areas.Api.Controllers.Backups.Models [LocalizedRequired] public BackupJobDto[] Items { get; set; } - public static BackupJobsDto FromBackups(IEnumerable<IBackupJob> backups, Resources resources) + public static BackupJobsDto FromDomain(IEnumerable<IBackupJob> backups, Resources resources) { var result = new BackupJobsDto { - Items = backups.Select(x => BackupJobDto.FromBackup(x, resources)).ToArray() + Items = backups.Select(x => BackupJobDto.FromDomain(x, resources)).ToArray() }; return result.CreateLinks(resources); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreJobDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreJobDto.cs index bcae691d2..76084dcfc 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreJobDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreJobDto.cs @@ -41,7 +41,7 @@ namespace Squidex.Areas.Api.Controllers.Backups.Models /// </summary> public JobStatus Status { get; set; } - public static RestoreJobDto FromJob(IRestoreJob job) + public static RestoreJobDto FromDomain(IRestoreJob job) { return SimpleMapper.Map(job, new RestoreJobDto()); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs b/backend/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs index bde9f3579..857b58f58 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs @@ -49,7 +49,7 @@ namespace Squidex.Areas.Api.Controllers.Backups return NotFound(); } - var response = RestoreJobDto.FromJob(job); + var response = RestoreJobDto.FromDomain(job); return Ok(response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/BulkResultDto.cs b/backend/src/Squidex/Areas/Api/Controllers/BulkResultDto.cs index 6539839bc..a6bc6df8a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/BulkResultDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/BulkResultDto.cs @@ -35,7 +35,7 @@ namespace Squidex.Areas.Api.Controllers [Obsolete("Use 'id' field now.")] public DomainId? ContentId => Id; - public static BulkResultDto FromBulkResult(BulkUpdateResultItem result, HttpContext httpContext) + public static BulkResultDto FromDomain(BulkUpdateResultItem result, HttpContext httpContext) { var error = result.Exception?.ToErrorDto(httpContext).Error; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs index b37657bd0..6ed316ef0 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs @@ -83,7 +83,7 @@ namespace Squidex.Areas.Api.Controllers.Comments var response = Deferred.Response(() => { - return CommentsDto.FromResult(result); + return CommentsDto.FromDomain(result); }); Response.Headers[HeaderNames.ETag] = result.Version.ToString(CultureInfo.InvariantCulture); @@ -113,7 +113,7 @@ namespace Squidex.Areas.Api.Controllers.Comments await CommandBus.PublishAsync(command); - var response = CommentDto.FromCommand(command); + var response = CommentDto.FromDomain(command); return CreatedAtAction(nameof(GetComments), new { app, commentsId }, response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs index 71f8d86f1..210a2bbc6 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs @@ -44,12 +44,14 @@ namespace Squidex.Areas.Api.Controllers.Comments.Models /// </summary> public Uri? Url { get; set; } - public static CommentDto FromComment(Comment comment) + public static CommentDto FromDomain(Comment comment) { - return SimpleMapper.Map(comment, new CommentDto()); + var result = SimpleMapper.Map(comment, new CommentDto()); + + return result; } - public static CommentDto FromCommand(CreateComment command) + public static CommentDto FromDomain(CreateComment command) { var time = SystemClock.Instance.GetCurrentInstant(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs index 0c62d28cb..447a361ec 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentsDto.cs @@ -32,15 +32,17 @@ namespace Squidex.Areas.Api.Controllers.Comments.Models /// </summary> public long Version { get; set; } - public static CommentsDto FromResult(CommentsResult result) + public static CommentsDto FromDomain(CommentsResult comments) { - return new CommentsDto + var result = new CommentsDto { - CreatedComments = result.CreatedComments.Select(CommentDto.FromComment).ToArray(), - UpdatedComments = result.UpdatedComments.Select(CommentDto.FromComment).ToArray(), - DeletedComments = result.DeletedComments, - Version = result.Version + CreatedComments = comments.CreatedComments.Select(CommentDto.FromDomain).ToArray(), + UpdatedComments = comments.UpdatedComments.Select(CommentDto.FromDomain).ToArray(), + DeletedComments = comments.DeletedComments, + Version = comments.Version }; + + return result; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs index 4d1b439ac..b9d6ec28a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs @@ -57,7 +57,7 @@ namespace Squidex.Areas.Api.Controllers.Comments.Notifications var response = Deferred.Response(() => { - return CommentsDto.FromResult(result); + return CommentsDto.FromDomain(result); }); Response.Headers[HeaderNames.ETag] = result.Version.ToString(CultureInfo.InvariantCulture); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs index cc117451d..202b82875 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs @@ -209,7 +209,7 @@ namespace Squidex.Areas.Api.Controllers.Contents var response = Deferred.Response(() => { - return ContentDto.FromContent(content, Resources); + return ContentDto.FromDomain(content, Resources); }); return Ok(response); @@ -331,7 +331,7 @@ namespace Squidex.Areas.Api.Controllers.Contents return NotFound(); } - var response = ContentDto.FromContent(content, Resources); + var response = ContentDto.FromDomain(content, Resources); return Ok(response.Data); } @@ -391,7 +391,7 @@ namespace Squidex.Areas.Api.Controllers.Contents var context = await CommandBus.PublishAsync(command); var result = context.Result<BulkUpdateResult>(); - var response = result.Select(x => BulkResultDto.FromBulkResult(x, HttpContext)).ToArray(); + var response = result.Select(x => BulkResultDto.FromDomain(x, HttpContext)).ToArray(); return Ok(response); } @@ -422,7 +422,7 @@ namespace Squidex.Areas.Api.Controllers.Contents var context = await CommandBus.PublishAsync(command); var result = context.Result<BulkUpdateResult>(); - var response = result.Select(x => BulkResultDto.FromBulkResult(x, HttpContext)).ToArray(); + var response = result.Select(x => BulkResultDto.FromDomain(x, HttpContext)).ToArray(); return Ok(response); } @@ -658,7 +658,7 @@ namespace Squidex.Areas.Api.Controllers.Contents var context = await CommandBus.PublishAsync(command); var result = context.Result<IEnrichedContentEntity>(); - var response = ContentDto.FromContent(result, Resources); + var response = ContentDto.FromDomain(result, Resources); return response; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs index 693b7a6f7..ddc270c91 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs @@ -117,7 +117,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// </summary> public long Version { get; set; } - public static ContentDto FromContent(IEnrichedContentEntity content, Resources resources) + public static ContentDto FromDomain(IEnrichedContentEntity content, Resources resources) { var response = SimpleMapper.Map(content, new ContentDto { @@ -136,7 +136,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models if (content.ReferenceFields != null) { - response.ReferenceFields = content.ReferenceFields.Select(FieldDto.FromField).ToArray(); + response.ReferenceFields = content.ReferenceFields.Select(FieldDto.FromDomain).ToArray(); } if (content.ScheduleJob != null) diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs index e5f50d827..9658e965a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs @@ -38,7 +38,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models var result = new ContentsDto { Total = contents.Total, - Items = contents.Select(x => ContentDto.FromContent(x, resources)).ToArray() + Items = contents.Select(x => ContentDto.FromDomain(x, resources)).ToArray() }; if (schema != null) @@ -55,7 +55,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models { var allStatuses = await workflow.GetAllAsync(schema); - Statuses = allStatuses.Select(StatusInfoDto.FromStatusInfo).ToArray(); + Statuses = allStatuses.Select(StatusInfoDto.FromDomain).ToArray(); } private async Task CreateLinksAsync(Resources resources, IContentWorkflow workflow, ISchemaEntity schema) diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs index c2c14958e..aae009db4 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs @@ -24,9 +24,11 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models [LocalizedRequired] public string Color { get; set; } - public static StatusInfoDto FromStatusInfo(StatusInfo statusInfo) + public static StatusInfoDto FromDomain(StatusInfo statusInfo) { - return new StatusInfoDto { Status = statusInfo.Status, Color = statusInfo.Color }; + var result = new StatusInfoDto { Status = statusInfo.Status, Color = statusInfo.Color }; + + return result; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/EventConsumersController.cs b/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/EventConsumersController.cs index ed6a27f31..8bf65088f 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/EventConsumersController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/EventConsumersController.cs @@ -34,7 +34,7 @@ namespace Squidex.Areas.Api.Controllers.EventConsumers { var eventConsumers = await GetGrain().GetConsumersAsync(); - var response = EventConsumersDto.FromResults(eventConsumers.Value, Resources); + var response = EventConsumersDto.FromDomain(eventConsumers.Value, Resources); return Ok(response); } @@ -47,7 +47,7 @@ namespace Squidex.Areas.Api.Controllers.EventConsumers { var eventConsumer = await GetGrain().StartAsync(consumerName); - var response = EventConsumerDto.FromEventConsumerInfo(eventConsumer, Resources); + var response = EventConsumerDto.FromDomain(eventConsumer, Resources); return Ok(response); } @@ -60,7 +60,7 @@ namespace Squidex.Areas.Api.Controllers.EventConsumers { var eventConsumer = await GetGrain().StopAsync(consumerName); - var response = EventConsumerDto.FromEventConsumerInfo(eventConsumer, Resources); + var response = EventConsumerDto.FromDomain(eventConsumer, Resources); return Ok(response); } @@ -73,7 +73,7 @@ namespace Squidex.Areas.Api.Controllers.EventConsumers { var eventConsumer = await GetGrain().ResetAsync(consumerName); - var response = EventConsumerDto.FromEventConsumerInfo(eventConsumer, Resources); + var response = EventConsumerDto.FromDomain(eventConsumer, Resources); return Ok(response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumerDto.cs b/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumerDto.cs index 20d081d4b..882d09832 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumerDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumerDto.cs @@ -25,7 +25,7 @@ namespace Squidex.Areas.Api.Controllers.EventConsumers.Models public string? Position { get; set; } - public static EventConsumerDto FromEventConsumerInfo(EventConsumerInfo eventConsumerInfo, Resources resources) + public static EventConsumerDto FromDomain(EventConsumerInfo eventConsumerInfo, Resources resources) { var result = SimpleMapper.Map(eventConsumerInfo, new EventConsumerDto()); diff --git a/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumersDto.cs b/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumersDto.cs index 9aa80ba0f..1c3ece7c7 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumersDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/EventConsumers/Models/EventConsumersDto.cs @@ -17,11 +17,11 @@ namespace Squidex.Areas.Api.Controllers.EventConsumers.Models /// </summary> public EventConsumerDto[] Items { get; set; } - public static EventConsumersDto FromResults(IEnumerable<EventConsumerInfo> items, Resources resources) + public static EventConsumersDto FromDomain(IEnumerable<EventConsumerInfo> items, Resources resources) { var result = new EventConsumersDto { - Items = items.Select(x => EventConsumerDto.FromEventConsumerInfo(x, resources)).ToArray() + Items = items.Select(x => EventConsumerDto.FromDomain(x, resources)).ToArray() }; return result.CreateLinks(resources); diff --git a/backend/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs b/backend/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs index 0b4b69ef0..ebd88b053 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs @@ -46,7 +46,7 @@ namespace Squidex.Areas.Api.Controllers.History { var events = await historyService.QueryByChannelAsync(AppId, channel, 100, HttpContext.RequestAborted); - var response = events.Select(HistoryEventDto.FromHistoryEvent).Where(x => x.Message != null).ToArray(); + var response = events.Select(HistoryEventDto.FromDomain).Where(x => x.Message != null).ToArray(); return Ok(response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs b/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs index c43b869d2..404b34452 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs @@ -48,9 +48,11 @@ namespace Squidex.Areas.Api.Controllers.History.Models /// </summary> public long Version { get; set; } - public static HistoryEventDto FromHistoryEvent(ParsedHistoryEvent historyEvent) + public static HistoryEventDto FromDomain(ParsedHistoryEvent historyEvent) { - return SimpleMapper.Map(historyEvent, new HistoryEventDto { EventId = historyEvent.Id }); + var result = SimpleMapper.Map(historyEvent, new HistoryEventDto { EventId = historyEvent.Id }); + + return result; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/LanguageDto.cs b/backend/src/Squidex/Areas/Api/Controllers/LanguageDto.cs index 94f892c74..4354e1ee3 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/LanguageDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/LanguageDto.cs @@ -31,9 +31,11 @@ namespace Squidex.Areas.Api.Controllers [LocalizedRequired] public string NativeName { get; set; } - public static LanguageDto FromLanguage(Language language) + public static LanguageDto FromDomain(Language language) { - return SimpleMapper.Map(language, new LanguageDto()); + var result = SimpleMapper.Map(language, new LanguageDto()); + + return result; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs index 0118399c9..879902d63 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs @@ -41,7 +41,7 @@ namespace Squidex.Areas.Api.Controllers.Languages { var response = Deferred.Response(() => { - return Language.AllLanguages.Select(LanguageDto.FromLanguage).ToArray(); + return Language.AllLanguages.Select(LanguageDto.FromDomain).ToArray(); }); Response.Headers[HeaderNames.ETag] = "1"; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs b/backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs index 61e825ae6..95df58994 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs @@ -52,7 +52,7 @@ namespace Squidex.Areas.Api.Controllers.Plans var response = Deferred.Response(() => { - return AppPlansDto.FromApp(App, appPlansProvider, hasPortal); + return AppPlansDto.FromDomain(App, appPlansProvider, hasPortal); }); Response.Headers[HeaderNames.ETag] = App.ToEtag(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/AppPlansDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/AppPlansDto.cs index 268de7a82..626149f20 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/AppPlansDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/AppPlansDto.cs @@ -34,19 +34,19 @@ namespace Squidex.Areas.Api.Controllers.Plans.Models /// </summary> public bool HasPortal { get; set; } - public static AppPlansDto FromApp(IAppEntity app, IAppPlansProvider plans, bool hasPortal) + public static AppPlansDto FromDomain(IAppEntity app, IAppPlansProvider plans, bool hasPortal) { var (_, planId) = plans.GetPlanForApp(app); - var response = new AppPlansDto + var result = new AppPlansDto { CurrentPlanId = planId, - Plans = plans.GetAvailablePlans().Select(PlanDto.FromPlan).ToArray(), + Plans = plans.GetAvailablePlans().Select(PlanDto.FromDomain).ToArray(), PlanOwner = app.Plan?.Owner.Identifier, HasPortal = hasPortal }; - return response; + return result; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs index f692a8907..95590d68b 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs @@ -71,9 +71,11 @@ namespace Squidex.Areas.Api.Controllers.Plans.Models /// </summary> public int MaxContributors { get; set; } - public static PlanDto FromPlan(IAppLimitsPlan plan) + public static PlanDto FromDomain(IAppLimitsPlan plan) { - return SimpleMapper.Map(plan, new PlanDto()); + var result = SimpleMapper.Map(plan, new PlanDto()); + + return result; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleTriggerDtoFactory.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleTriggerDtoFactory.cs index 0ccc47667..a66c8d7fa 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleTriggerDtoFactory.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleTriggerDtoFactory.cs @@ -52,7 +52,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models.Converters public RuleTriggerDto Visit(ContentChangedTriggerV2 trigger) { - var schemas = trigger.Schemas?.Select(ContentChangedRuleTriggerSchemaDto.FromTrigger).ToArray(); + var schemas = trigger.Schemas?.Select(ContentChangedRuleTriggerSchemaDto.FromDomain).ToArray(); return new ContentChangedRuleTriggerDto { Schemas = schemas, HandleAll = trigger.HandleAll }; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs index 34fe1e509..f8bf40c47 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs @@ -90,7 +90,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// </summary> public Instant? LastExecuted { get; set; } - public static RuleDto FromRule(IEnrichedRuleEntity rule, bool canRun, IRuleRunnerService ruleRunnerService, Resources resources) + public static RuleDto FromDomain(IEnrichedRuleEntity rule, bool canRun, IRuleRunnerService ruleRunnerService, Resources resources) { var result = new RuleDto(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleElementDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleElementDto.cs index 5abfea0e1..9ea19585a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleElementDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleElementDto.cs @@ -51,7 +51,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models [LocalizedRequired] public RuleElementPropertyDto[] Properties { get; set; } - public static RuleElementDto FromDefinition(RuleActionDefinition definition) + public static RuleElementDto FromDomain(RuleActionDefinition definition) { var result = SimpleMapper.Map(definition, new RuleElementDto()); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs index 475692649..304077089 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs @@ -64,7 +64,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// </summary> public RuleJobResult JobResult { get; set; } - public static RuleEventDto FromRuleEvent(IRuleEventEntity ruleEvent, Resources resources) + public static RuleEventDto FromDomain(IRuleEventEntity ruleEvent, Resources resources) { var result = new RuleEventDto(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventsDto.cs index 4bca9503e..76acf4699 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventsDto.cs @@ -25,12 +25,12 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// </summary> public long Total { get; set; } - public static RuleEventsDto FromRuleEvents(IResultList<IRuleEventEntity> ruleEvents, Resources resources, DomainId? ruleId) + public static RuleEventsDto FromDomain(IResultList<IRuleEventEntity> ruleEvents, Resources resources, DomainId? ruleId) { var result = new RuleEventsDto { Total = ruleEvents.Total, - Items = ruleEvents.Select(x => RuleEventDto.FromRuleEvent(x, resources)).ToArray() + Items = ruleEvents.Select(x => RuleEventDto.FromDomain(x, resources)).ToArray() }; return result.CreateLinks(resources, ruleId); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs index eaa646ff0..660dd0f9d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RulesDto.cs @@ -32,7 +32,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models var result = new RulesDto { - Items = items.Select(x => RuleDto.FromRule(x, runningRuleId == null, ruleRunnerService, resources)).ToArray() + Items = items.Select(x => RuleDto.FromDomain(x, runningRuleId == null, ruleRunnerService, resources)).ToArray() }; result.RunningRuleId = runningRuleId; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventDto.cs index 15d79df64..f3fe4b1d5 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventDto.cs @@ -52,7 +52,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models [Required] public List<SkipReason> SkipReasons { get; set; } - public static SimulatedRuleEventDto FromSimulatedRuleEvent(SimulatedRuleEvent ruleEvent) + public static SimulatedRuleEventDto FromDomain(SimulatedRuleEvent ruleEvent) { var result = SimpleMapper.Map(ruleEvent, new SimulatedRuleEventDto { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventsDto.cs index 5681b2aa6..852184868 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/SimulatedRuleEventsDto.cs @@ -24,12 +24,12 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// </summary> public long Total { get; set; } - public static SimulatedRuleEventsDto FromSimulatedRuleEvents(IList<SimulatedRuleEvent> events) + public static SimulatedRuleEventsDto FromDomain(IList<SimulatedRuleEvent> events) { var result = new SimulatedRuleEventsDto { Total = events.Count, - Items = events.Select(SimulatedRuleEventDto.FromSimulatedRuleEvent).ToArray() + Items = events.Select(SimulatedRuleEventDto.FromDomain).ToArray() }; return result; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs index 7a575ed6f..e05b642f5 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/Triggers/ContentChangedRuleTriggerSchemaDto.cs @@ -28,9 +28,11 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models.Triggers return SimpleMapper.Map(this, new ContentChangedTriggerSchemaV2()); } - public static ContentChangedRuleTriggerSchemaDto FromTrigger(ContentChangedTriggerSchemaV2 trigger) + public static ContentChangedRuleTriggerSchemaDto FromDomain(ContentChangedTriggerSchemaV2 trigger) { - return SimpleMapper.Map(trigger, new ContentChangedRuleTriggerSchemaDto()); + var result = SimpleMapper.Map(trigger, new ContentChangedRuleTriggerSchemaDto()); + + return result; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs index 84d936d12..830bc34d9 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs @@ -70,7 +70,7 @@ namespace Squidex.Areas.Api.Controllers.Rules var response = Deferred.Response(() => { - return ruleRegistry.Actions.ToDictionary(x => x.Key, x => RuleElementDto.FromDefinition(x.Value)); + return ruleRegistry.Actions.ToDictionary(x => x.Key, x => RuleElementDto.FromDomain(x.Value)); }); Response.Headers[HeaderNames.ETag] = etag; @@ -305,7 +305,7 @@ namespace Squidex.Areas.Api.Controllers.Rules var simulation = await ruleRunnerService.SimulateAsync(rule, HttpContext.RequestAborted); - var response = SimulatedRuleEventsDto.FromSimulatedRuleEvents(simulation); + var response = SimulatedRuleEventsDto.FromDomain(simulation); return Ok(response); } @@ -350,7 +350,7 @@ namespace Squidex.Areas.Api.Controllers.Rules { var ruleEvents = await ruleEventsRepository.QueryByAppAsync(AppId, ruleId, skip, take, HttpContext.RequestAborted); - var response = RuleEventsDto.FromRuleEvents(ruleEvents, Resources, ruleId); + var response = RuleEventsDto.FromDomain(ruleEvents, Resources, ruleId); return Ok(response); } @@ -476,7 +476,7 @@ namespace Squidex.Areas.Api.Controllers.Rules var runningRuleId = await ruleRunnerService.GetRunningRuleIdAsync(Context.App.Id, HttpContext.RequestAborted); var result = context.Result<IEnrichedRuleEntity>(); - var response = RuleDto.FromRule(result, runningRuleId == null, ruleRunnerService, Resources); + var response = RuleDto.FromDomain(result, runningRuleId == null, ruleRunnerService, Resources); return response; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs index e9e6272dd..67aa6c1c8 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs @@ -59,7 +59,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// </summary> public List<NestedFieldDto>? Nested { get; set; } - public static NestedFieldDto FromField(NestedField field) + public static NestedFieldDto FromDomain(NestedField field) { var properties = FieldPropertiesDtoFactory.Create(field.RawProperties); @@ -74,7 +74,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models return result; } - public static FieldDto FromField(RootField field) + public static FieldDto FromDomain(RootField field) { var properties = FieldPropertiesDtoFactory.Create(field.RawProperties); @@ -93,7 +93,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models foreach (var nestedField in arrayField.Fields) { - result.Nested.Add(FromField(nestedField)); + result.Nested.Add(FromDomain(nestedField)); } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldRuleDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldRuleDto.cs index c08d1d37b..5a24219ed 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldRuleDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldRuleDto.cs @@ -31,7 +31,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// </summary> public string? Condition { get; set; } - public static FieldRuleDto FromFieldRule(FieldRule fieldRule) + public static FieldRuleDto FromDomain(FieldRule fieldRule) { return SimpleMapper.Map(fieldRule, new FieldRuleDto()); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs index dcc166eff..0c36075ae 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs @@ -123,7 +123,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models [LocalizedRequired] public List<FieldDto> Fields { get; set; } - public static SchemaDto FromSchema(ISchemaEntity schema, Resources resources) + public static SchemaDto FromDomain(ISchemaEntity schema, Resources resources) { var result = new SchemaDto(); @@ -132,13 +132,13 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models SimpleMapper.Map(schema.SchemaDef.Scripts, result.Scripts); SimpleMapper.Map(schema.SchemaDef.Properties, result.Properties); - result.FieldRules = schema.SchemaDef.FieldRules.Select(FieldRuleDto.FromFieldRule).ToList(); + result.FieldRules = schema.SchemaDef.FieldRules.Select(FieldRuleDto.FromDomain).ToList(); result.Fields = new List<FieldDto>(); foreach (var field in schema.SchemaDef.Fields) { - result.Fields.Add(FieldDto.FromField(field)); + result.Fields.Add(FieldDto.FromDomain(field)); } result.CreateLinks(resources); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemasDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemasDto.cs index 58a0186fd..90ef4942f 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemasDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemasDto.cs @@ -17,11 +17,11 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// </summary> public SchemaDto[] Items { get; set; } - public static SchemasDto FromSchemas(IList<ISchemaEntity> schemas, Resources resources) + public static SchemasDto FromDomain(IList<ISchemaEntity> schemas, Resources resources) { var result = new SchemasDto { - Items = schemas.Select(x => SchemaDto.FromSchema(x, resources)).ToArray() + Items = schemas.Select(x => SchemaDto.FromDomain(x, resources)).ToArray() }; return result.CreateLinks(resources); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs index 483684f39..9fc4dadd8 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs @@ -549,7 +549,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas var context = await CommandBus.PublishAsync(command); var result = context.Result<ISchemaEntity>(); - var response = SchemaDto.FromSchema(result, Resources); + var response = SchemaDto.FromDomain(result, Resources); return response; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs index 4c4f8dded..435983aa9 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs @@ -56,7 +56,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas var response = Deferred.Response(() => { - return SchemasDto.FromSchemas(schemas, Resources); + return SchemasDto.FromDomain(schemas, Resources); }); Response.Headers[HeaderNames.ETag] = schemas.ToEtag(); @@ -82,7 +82,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas { var response = Deferred.Response(() => { - return SchemaDto.FromSchema(Schema, Resources); + return SchemaDto.FromDomain(Schema, Resources); }); Response.Headers[HeaderNames.ETag] = Schema.ToEtag(); @@ -396,7 +396,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas var context = await CommandBus.PublishAsync(command); var result = context.Result<ISchemaEntity>(); - var response = SchemaDto.FromSchema(result, Resources); + var response = SchemaDto.FromDomain(result, Resources); return response; } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Search/Models/SearchResultDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Search/Models/SearchResultDto.cs index 90f431ffc..f4db011fa 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Search/Models/SearchResultDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Search/Models/SearchResultDto.cs @@ -31,20 +31,18 @@ namespace Squidex.Areas.Api.Controllers.Search.Models /// </summary> public string? Label { get; set; } - public static SearchResultDto FromSearchResult(SearchResult searchResult) + public static SearchResultDto FromDomain(SearchResult searchResult) { - var result = new SearchResultDto(); + var result = SimpleMapper.Map(searchResult, new SearchResultDto()); - SimpleMapper.Map(searchResult, result); - - result.CreateLinks(searchResult); - - return result; + return result.CreateLinks(searchResult); } - protected virtual void CreateLinks(SearchResult searchResult) + protected SearchResultDto CreateLinks(SearchResult searchResult) { AddGetLink("url", searchResult.Url); + + return this; } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs b/backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs index 540a1ac55..f7080b93b 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs @@ -46,7 +46,7 @@ namespace Squidex.Areas.Api.Controllers.Search { var result = await searchManager.SearchAsync(query, Context, HttpContext.RequestAborted); - var response = result.Select(SearchResultDto.FromSearchResult).ToArray(); + var response = result.Select(SearchResultDto.FromDomain).ToArray(); return Ok(response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsageDtoDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsageDtoDto.cs index 770761317..97db80196 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsageDtoDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsageDtoDto.cs @@ -59,7 +59,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics.Models [LocalizedRequired] public Dictionary<string, CallsUsagePerDateDto[]> Details { get; set; } - public static CallsUsageDtoDto FromStats(IAppLimitsPlan plan, ApiStatsSummary summary, Dictionary<string, List<ApiStats>> details) + public static CallsUsageDtoDto FromDomain(IAppLimitsPlan plan, ApiStatsSummary summary, Dictionary<string, List<ApiStats>> details) { return new CallsUsageDtoDto { @@ -71,7 +71,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics.Models TotalCalls = summary.TotalCalls, MonthBytes = summary.MonthBytes, MonthCalls = summary.MonthCalls, - Details = details.ToDictionary(x => x.Key, x => x.Value.Select(CallsUsagePerDateDto.FromStats).ToArray()) + Details = details.ToDictionary(x => x.Key, x => x.Value.Select(CallsUsagePerDateDto.FromDomain).ToArray()) }; } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsagePerDateDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsagePerDateDto.cs index e11f13450..2011e0e78 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsagePerDateDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/CallsUsagePerDateDto.cs @@ -32,7 +32,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics.Models /// </summary> public double AverageElapsedMs { get; set; } - public static CallsUsagePerDateDto FromStats(ApiStats stats) + public static CallsUsagePerDateDto FromDomain(ApiStats stats) { var result = new CallsUsagePerDateDto { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/StorageUsagePerDateDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/StorageUsagePerDateDto.cs index 5108fcc98..acf0a69f1 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/StorageUsagePerDateDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Statistics/Models/StorageUsagePerDateDto.cs @@ -27,7 +27,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics.Models /// </summary> public long TotalSize { get; set; } - public static StorageUsagePerDateDto FromStats(AssetStats stats) + public static StorageUsagePerDateDto FromDomain(AssetStats stats) { var result = new StorageUsagePerDateDto { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs index c517606e7..9c2da95c6 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs @@ -104,7 +104,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics var (plan, _) = appPlansProvider.GetPlanForApp(App); - var response = CallsUsageDtoDto.FromStats(plan, summary, details); + var response = CallsUsageDtoDto.FromDomain(plan, summary, details); return Ok(response); } @@ -158,7 +158,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics var usages = await assetStatsRepository.QueryAsync(AppId, fromDate.Date, toDate.Date); - var models = usages.Select(StorageUsagePerDateDto.FromStats).ToArray(); + var models = usages.Select(StorageUsagePerDateDto.FromDomain).ToArray(); return Ok(models); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDetailsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDetailsDto.cs new file mode 100644 index 000000000..0c7215b85 --- /dev/null +++ b/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDetailsDto.cs @@ -0,0 +1,40 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure.Validation; +using Squidex.Web; + +namespace Squidex.Areas.Api.Controllers.Templates.Models +{ + public class TemplateDetailsDto : Resource + { + /// <summary> + /// The details of the template. + /// </summary> + [LocalizedRequired] + public string Details { get; set; } + + public static TemplateDetailsDto FromDomain(string name, string details, Resources resources) + { + var result = new TemplateDetailsDto + { + Details = details + }; + + return result.CreateLinks(name, resources); + } + + private TemplateDetailsDto CreateLinks(string name, Resources resources) + { + var values = new { name }; + + AddSelfLink(resources.Url<TemplatesController>(c => nameof(c.GetTemplate), values)); + + return this; + } + } +} diff --git a/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDto.cs new file mode 100644 index 000000000..264b5e4b9 --- /dev/null +++ b/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplateDto.cs @@ -0,0 +1,51 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Entities.Apps.Templates; +using Squidex.Infrastructure.Reflection; +using Squidex.Infrastructure.Validation; +using Squidex.Web; + +namespace Squidex.Areas.Api.Controllers.Templates.Models +{ + public sealed class TemplateDto : Resource + { + /// <summary> + /// The name of the template. + /// </summary> + [LocalizedRequired] + public string Name { get; set; } + + /// <summary> + /// The title of the template. + /// </summary> + [LocalizedRequired] + public string Title { get; set; } + + /// <summary> + /// The description of the template. + /// </summary> + [LocalizedRequired] + public string Description { get; set; } + + public static TemplateDto FromDomain(Template template, Resources resources) + { + var result = SimpleMapper.Map(template, new TemplateDto()); + + return result.CreateLinks(resources); + } + + private TemplateDto CreateLinks(Resources resources) + { + var values = new { name = Name }; + + AddSelfLink(resources.Url<TemplatesController>(c => nameof(c.GetTemplate), values)); + + return this; + } + } +} diff --git a/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplatesDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplatesDto.cs new file mode 100644 index 000000000..5c1259563 --- /dev/null +++ b/backend/src/Squidex/Areas/Api/Controllers/Templates/Models/TemplatesDto.cs @@ -0,0 +1,37 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Entities.Apps.Templates; +using Squidex.Web; + +namespace Squidex.Areas.Api.Controllers.Templates.Models +{ + public sealed class TemplatesDto : Resource + { + /// <summary> + /// The event consumers. + /// </summary> + public TemplateDto[] Items { get; set; } + + public static TemplatesDto FromDomain(IEnumerable<Template> items, Resources resources) + { + var result = new TemplatesDto + { + Items = items.Select(x => TemplateDto.FromDomain(x, resources)).ToArray() + }; + + return result.CreateLinks(resources); + } + + private TemplatesDto CreateLinks(Resources resources) + { + AddSelfLink(resources.Url<TemplatesController>(c => nameof(c.GetTemplates))); + + return this; + } + } +} diff --git a/backend/src/Squidex/Areas/Api/Controllers/Templates/TemplatesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Templates/TemplatesController.cs new file mode 100644 index 000000000..882a9fad7 --- /dev/null +++ b/backend/src/Squidex/Areas/Api/Controllers/Templates/TemplatesController.cs @@ -0,0 +1,75 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Microsoft.AspNetCore.Mvc; +using Squidex.Areas.Api.Controllers.Templates.Models; +using Squidex.Domain.Apps.Entities.Apps.Templates; +using Squidex.Infrastructure.Commands; +using Squidex.Web; + +namespace Squidex.Areas.Api.Controllers.Templates +{ + /// <summary> + /// Readonly API for news items. + /// </summary> + [ApiExplorerSettings(GroupName = nameof(Templates))] + public sealed class TemplatesController : ApiController + { + private readonly TemplatesClient templatesClient; + + public TemplatesController(ICommandBus commandBus, TemplatesClient templatesClient) + : base(commandBus) + { + this.templatesClient = templatesClient; + } + + /// <summary> + /// Get all templates. + /// </summary> + /// <returns> + /// 200 => Templates returned. + /// </returns> + [HttpGet] + [Route("templates/")] + [ProducesResponseType(typeof(TemplatesDto), StatusCodes.Status200OK)] + [ApiPermission] + public async Task<IActionResult> GetTemplates() + { + var templates = await templatesClient.GetTemplatesAsync(HttpContext.RequestAborted); + + var response = TemplatesDto.FromDomain(templates, Resources); + + return Ok(response); + } + + /// <summary> + /// Get template details. + /// </summary> + /// <param name="name">The name of the template.</param> + /// <returns> + /// 200 => Template returned. + /// 404 => Template not found. + /// </returns> + [HttpGet] + [Route("templates/{name}")] + [ProducesResponseType(typeof(TemplateDetailsDto), StatusCodes.Status200OK)] + [ApiPermission] + public async Task<IActionResult> GetTemplate(string name) + { + var details = await templatesClient.GetDetailAsync(name, HttpContext.RequestAborted); + + if (details == null) + { + return NotFound(); + } + + var response = TemplateDetailsDto.FromDomain(name, details, Resources); + + return Ok(response); + } + } +} diff --git a/backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs index 6eb301ff9..76aad2981 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs @@ -22,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.Translations.Models /// </summary> public string? Text { get; set; } - public static TranslationDto FromTranslation(TranslationResult translation) + public static TranslationDto FromDomain(TranslationResult translation) { return SimpleMapper.Map(translation, new TranslationDto()); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs index affed08e7..398a3708f 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs @@ -44,7 +44,7 @@ namespace Squidex.Areas.Api.Controllers.Translations public async Task<IActionResult> PostTranslation(string app, [FromBody] TranslateDto request) { var result = await translator.TranslateAsync(request.Text, request.TargetLanguage, request.SourceLanguage, HttpContext.RequestAborted); - var response = TranslationDto.FromTranslation(result); + var response = TranslationDto.FromDomain(result); return Ok(response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Users/Models/ResourcesDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Users/Models/ResourcesDto.cs index d41383921..a4830efa7 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Users/Models/ResourcesDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Users/Models/ResourcesDto.cs @@ -15,7 +15,7 @@ namespace Squidex.Areas.Api.Controllers.Users.Models { public sealed class ResourcesDto : Resource { - public static ResourcesDto FromResources(Resources resources) + public static ResourcesDto FromDomain(Resources resources) { var result = new ResourcesDto(); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UserDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UserDto.cs index c7f3b571b..23ee2d790 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UserDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UserDto.cs @@ -45,12 +45,12 @@ namespace Squidex.Areas.Api.Controllers.Users.Models [LocalizedRequired] public IEnumerable<string> Permissions { get; set; } - public static UserDto FromUser(IUser user, Resources resources) + public static UserDto FromDomain(IUser user, Resources resources) { - var userPermssions = user.Claims.Permissions().ToIds(); - var userName = user.Claims.DisplayName()!; + var result = SimpleMapper.Map(user, new UserDto()); - var result = SimpleMapper.Map(user, new UserDto { DisplayName = userName, Permissions = userPermssions }); + result.DisplayName = user.Claims.DisplayName()!; + result.Permissions = user.Claims.Permissions().ToIds(); return result.CreateLinks(resources); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UsersDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UsersDto.cs index 0e8891c40..6833018d2 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UsersDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Users/Models/UsersDto.cs @@ -24,12 +24,12 @@ namespace Squidex.Areas.Api.Controllers.Users.Models [LocalizedRequired] public UserDto[] Items { get; set; } - public static UsersDto FromResults(IEnumerable<IUser> items, long total, Resources resources) + public static UsersDto FromDomain(IEnumerable<IUser> items, long total, Resources resources) { var result = new UsersDto { Total = total, - Items = items.Select(x => UserDto.FromUser(x, resources)).ToArray() + Items = items.Select(x => UserDto.FromDomain(x, resources)).ToArray() }; return result.CreateLinks(resources); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Users/UserManagementController.cs b/backend/src/Squidex/Areas/Api/Controllers/Users/UserManagementController.cs index 6f75cd09a..f7f6eab44 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Users/UserManagementController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Users/UserManagementController.cs @@ -35,7 +35,7 @@ namespace Squidex.Areas.Api.Controllers.Users { var users = await userService.QueryAsync(query, take, skip, HttpContext.RequestAborted); - var response = UsersDto.FromResults(users, users.Total, Resources); + var response = UsersDto.FromDomain(users, users.Total, Resources); return Ok(response); } @@ -53,7 +53,7 @@ namespace Squidex.Areas.Api.Controllers.Users return NotFound(); } - var response = UserDto.FromUser(user, Resources); + var response = UserDto.FromDomain(user, Resources); return Ok(response); } @@ -66,7 +66,7 @@ namespace Squidex.Areas.Api.Controllers.Users { var user = await userService.CreateAsync(request.Email, request.ToValues(), ct: HttpContext.RequestAborted); - var response = UserDto.FromUser(user, Resources); + var response = UserDto.FromDomain(user, Resources); return Ok(response); } @@ -79,7 +79,7 @@ namespace Squidex.Areas.Api.Controllers.Users { var user = await userService.UpdateAsync(id, request.ToValues(), ct: HttpContext.RequestAborted); - var response = UserDto.FromUser(user, Resources); + var response = UserDto.FromDomain(user, Resources); return Ok(response); } @@ -97,7 +97,7 @@ namespace Squidex.Areas.Api.Controllers.Users var user = await userService.LockAsync(id, HttpContext.RequestAborted); - var response = UserDto.FromUser(user, Resources); + var response = UserDto.FromDomain(user, Resources); return Ok(response); } @@ -115,7 +115,7 @@ namespace Squidex.Areas.Api.Controllers.Users var user = await userService.UnlockAsync(id, HttpContext.RequestAborted); - var response = UserDto.FromUser(user, Resources); + var response = UserDto.FromDomain(user, Resources); return Ok(response); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs b/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs index e10853a4a..13640c40a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs @@ -67,7 +67,7 @@ namespace Squidex.Areas.Api.Controllers.Users [ApiPermission] public IActionResult GetUserResources() { - var response = ResourcesDto.FromResources(Resources); + var response = ResourcesDto.FromDomain(Resources); return Ok(response); } @@ -92,7 +92,7 @@ namespace Squidex.Areas.Api.Controllers.Users { var users = await userResolver.QueryByEmailAsync(query, HttpContext.RequestAborted); - var response = users.Select(x => UserDto.FromUser(x, Resources)).ToArray(); + var response = users.Select(x => UserDto.FromDomain(x, Resources)).ToArray(); return Ok(response); } @@ -124,7 +124,7 @@ namespace Squidex.Areas.Api.Controllers.Users if (entity != null) { - var response = UserDto.FromUser(entity, Resources); + var response = UserDto.FromDomain(entity, Resources); return Ok(response); } diff --git a/backend/src/Squidex/Config/Domain/CommandsServices.cs b/backend/src/Squidex/Config/Domain/CommandsServices.cs index ae72381ba..93320e989 100644 --- a/backend/src/Squidex/Config/Domain/CommandsServices.cs +++ b/backend/src/Squidex/Config/Domain/CommandsServices.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps.DomainObject; using Squidex.Domain.Apps.Entities.Apps.Indexes; using Squidex.Domain.Apps.Entities.Apps.Invitation; using Squidex.Domain.Apps.Entities.Apps.Plans; -using Squidex.Domain.Apps.Entities.Apps.Templates; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.DomainObject; using Squidex.Domain.Apps.Entities.Comments.DomainObject; @@ -111,15 +111,6 @@ namespace Squidex.Config.Domain services.AddSingletonAs<AlwaysCreateClientCommandMiddleware>() .As<ICommandMiddleware>(); - services.AddSingletonAs<TemplateCommandMiddleware>() - .As<ICommandMiddleware>(); - - services.AddSingletonAs<CreateBlog>() - .As<ITemplate>(); - - services.AddSingletonAs<CreateProfile>() - .As<ITemplate>(); - services.AddSingletonAs<UsageTrackerCommandMiddleware>() .As<ICommandMiddleware>(); } diff --git a/backend/src/Squidex/Config/Domain/ContentsServices.cs b/backend/src/Squidex/Config/Domain/ContentsServices.cs index ca09bd1bd..e6598c47b 100644 --- a/backend/src/Squidex/Config/Domain/ContentsServices.cs +++ b/backend/src/Squidex/Config/Domain/ContentsServices.cs @@ -7,6 +7,7 @@ using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Entities; +using Squidex.Domain.Apps.Entities.Apps.Templates; using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Contents.Counter; using Squidex.Domain.Apps.Entities.Contents.DomainObject; @@ -97,6 +98,9 @@ namespace Squidex.Config.Domain services.AddSingletonAs<ContentsSearchSource>() .As<ISearchSource>(); + services.AddSingletonAs<TemplatesClient>() + .AsSelf(); + services.AddSingletonAs<GrainBootstrap<IContentSchedulerGrain>>() .AsSelf(); } diff --git a/backend/src/Squidex/wwwroot/images/add-blog.svg b/backend/src/Squidex/wwwroot/images/add-blog.svg deleted file mode 100644 index cecf13fa4..000000000 --- a/backend/src/Squidex/wwwroot/images/add-blog.svg +++ /dev/null @@ -1,38 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 64 64" xml:space="preserve"> - <style id="style8137" type="text/css"> - .st15{fill:#fff} - </style> - <style id="style8137-2" type="text/css"> - .st15{fill:#fff} - </style> - <style id="style8137-0" type="text/css"> - .st15{fill:#fff} - </style> - <g id="g4726" transform="translate(-67.875 31.5)"> - <g id="g8143-8" transform="translate(67.875 -31.5)"> - <path id="path8145-0" fill="#b4bcc1" d="M11.8 16c.2.4.2.9.2 1.3V19h1v-1.6c0-.7-.1-1.4-.4-2l-.1-3.1c-.4-1.2-.3-2.5.4-3.5.6-1 1.6-1.6 2.7-1.7H23.2c2.4 0 4.6.9 6.3 2.6l4.7 4.7c2.1 2.1 4.8 3.2 7.7 3.2H50v-2h-8.1c-2.4 0-4.6-.9-6.3-2.6l-4.7-4.7C28.8 6.1 26.1 5 23.2 5h-7.8c-1.7.2-3.2 1.1-4.2 2.6-1 1.6-1.2 3.5-.6 5.3l1.2 3.1z"/> - </g> - <g id="g8147-3" transform="translate(67.875 -31.5)"> - <path id="path8149-6" fill="#d7d7f9" d="M3 24v-4.5C3 15.9 5.9 13 9.5 13h12.8c1.7 0 3.4.7 4.6 1.9l7.2 9.2c1.2 1.2 2.9 1.9 4.6 1.9h7.8C55.1 26 61 30.9 61 39.5v15c0 3.6-3.9 6.5-7.5 6.5h-44C5.9 61 3 58.1 3 54.5V24z"/> - <path id="path8151-3" fill="#2e3842" d="M53.5 62h-44C5.4 62 2 58.6 2 54.5v-35C2 15.4 5.4 12 9.5 12h12.8c2 0 3.9.8 5.3 2.2l.1.1 7.2 9.2c1 1 2.4 1.6 3.8 1.6h7.8C55.9 25 62 30.7 62 39.5v15c0 4.3-4.5 7.5-8.5 7.5zm-44-48c-3 0-5.5 2.5-5.5 5.5v35.1c0 3 2.5 5.5 5.5 5.5h44.1c2.9 0 6.5-2.4 6.5-5.5v-15C60 31.8 54.8 27 46.5 27h-7.8c-2 0-3.9-.8-5.3-2.2l-.1-.1-7.2-9.2c-1-1-2.4-1.6-3.8-1.6L9.633 14z"/> - </g> - <g id="g8153" transform="translate(67.875 -31.5)"> - <path id="path8155" fill="#ededf9" d="M53 60H10c-3.8 0-6-2.2-6-6V20c0-3.8 2.2-6 6-6h12c2 0 3.6 1.2 4.7 2.3l.1.1 7 8.9c.6.5 2.1 1.7 4.5 1.5h7.3C54.7 26.9 60 31.3 60 39v15c0 3.6-2.8 6-7 6zM10 16c-2.7 0-4 1.3-4 4v34c0 2.7 1.3 4 4 4h43c2.3 0 5-1 5-4V39c0-8.8-7.9-10.1-12.5-10.1h-7.2c-2.2.1-4.4-.6-6-2.1l-.1-.1-7-8.9C24 16.5 23.1 16 22 16H10z"/> - </g> - <g id="g8197-0" transform="translate(67.875 -31.5)"> - <circle id="circle8199-9" cx="51.9" cy="12.1" r="11.1" fill="#3389ff"/> - <path id="path8201-7" fill="#fff" d="M51.9 24.2c-6.7 0-12.1-5.4-12.1-12.1C39.8 5.4 45.2 0 51.9 0 58.6 0 64 5.4 64 12.1c0 6.7-5.4 12.1-12.1 12.1zm0-22.2c-5.6 0-10.1 4.5-10.1 10.1s4.5 10.1 10.1 10.1S62 17.7 62 12.1 57.5 2 51.9 2z" class="st15"/> - </g> - <g id="g8203-4" transform="translate(67.875 -31.5)"> - <path id="path8205-6" fill="#fff" d="M57 13H47c-.6 0-1-.4-1-1s.4-1 1-1h10c.6 0 1 .4 1 1s-.4 1-1 1z" class="st15"/> - </g> - <g id="g8207-9" transform="translate(67.875 -31.5)"> - <path id="path8209-3" fill="#fff" d="M52 18c-.6 0-1-.4-1-1V7c0-.6.4-1 1-1s1 .4 1 1v10c0 .6-.4 1-1 1z" class="st15"/> - </g> - <g id="g4685" stroke="#b5b5ea" stroke-opacity="1" transform="matrix(.77563 0 0 .7719 73.711 -21.893)"> - <path id="path4174" fill="#b5b5ea" fill-opacity="1" stroke-width=".082" d="M12.888 47.387c-.96 0-1.775.34-2.447 1.018-.672.68-1.007 1.504-1.007 2.475 0 .97.335 1.795 1.007 2.474a3.313 3.313 0 002.447 1.019c.96 0 1.774-.34 2.446-1.019.672-.679 1.007-1.504 1.007-2.474 0-.97-.335-1.796-1.007-2.475a3.312 3.312 0 00-2.446-1.018z"/> - <path id="path4356" fill="none" fill-rule="evenodd" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="3.877" d="M10.506 31.413C33.49 31.538 32.491 53.4 32.491 53.4"/> - <path id="path4356-4" fill="none" fill-rule="evenodd" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-width="3.877" d="M10.344 39.427c14.616.08 13.982 13.986 13.982 13.986"/> - </g> - </g> -</svg> \ No newline at end of file diff --git a/backend/src/Squidex/wwwroot/images/add-identity.svg b/backend/src/Squidex/wwwroot/images/add-identity.svg deleted file mode 100644 index 30968a735..000000000 --- a/backend/src/Squidex/wwwroot/images/add-identity.svg +++ /dev/null @@ -1,27 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 64 64" xml:space="preserve"> - <style> - .st7{fill:#fff}.st9{fill:none;stroke:#b5b5ea;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10} - </style> - <g id="g8143"> - <path id="path8145" fill="#b4bcc1" d="M11.8 16c.2.4.2.9.2 1.3V19h1v-1.6c0-.7-.1-1.4-.4-2l-.1-3.1c-.4-1.2-.3-2.5.4-3.5.6-1 1.6-1.6 2.7-1.7H23.2c2.4 0 4.6.9 6.3 2.6l4.7 4.7c2.1 2.1 4.8 3.2 7.7 3.2H50v-2h-8.1c-2.4 0-4.6-.9-6.3-2.6l-4.7-4.7C28.8 6.1 26.1 5 23.2 5h-7.8c-1.7.2-3.2 1.1-4.2 2.6-1 1.6-1.2 3.5-.6 5.3l1.2 3.1z"/> - </g> - <g id="g8147"> - <path id="path8149" fill="#d7d7f9" d="M3 24v-4.5C3 15.9 5.9 13 9.5 13h12.8c1.7 0 3.4.7 4.6 1.9l7.2 9.2c1.2 1.2 2.9 1.9 4.6 1.9h7.8C55.1 26 61 30.9 61 39.5v15c0 3.6-3.9 6.5-7.5 6.5h-44C5.9 61 3 58.1 3 54.5V24z"/> - <path id="path8151" fill="#2e3842" d="M53.5 62h-44C5.4 62 2 58.6 2 54.5v-35C2 15.4 5.4 12 9.5 12h12.8c2 0 3.9.8 5.3 2.2l.1.1 7.2 9.2c1 1 2.4 1.6 3.8 1.6h7.8C55.9 25 62 30.7 62 39.5v15c0 4.3-4.5 7.5-8.5 7.5zm-44-48c-3 0-5.5 2.5-5.5 5.5v35.1c0 3 2.5 5.5 5.5 5.5h44.1c2.9 0 6.5-2.4 6.5-5.5v-15C60 31.8 54.8 27 46.5 27h-7.8c-2 0-3.9-.8-5.3-2.2l-.1-.1-7.2-9.2c-1-1-2.4-1.6-3.8-1.6H9.5v.1z"/> - </g> - <g id="g8153"> - <path id="path8155" fill="#ededf9" d="M53 60H10c-3.8 0-6-2.2-6-6V20c0-3.8 2.2-6 6-6h12c2 0 3.6 1.2 4.7 2.3l.1.1 7 8.9c.6.5 2.1 1.7 4.5 1.5h7.3C54.7 26.9 60 31.3 60 39v15c0 3.6-2.8 6-7 6zM10 16c-2.7 0-4 1.3-4 4v34c0 2.7 1.3 4 4 4h43c2.3 0 5-1 5-4V39c0-8.8-7.9-10.1-12.5-10.1h-7.2c-2.2.1-4.4-.6-6-2.1l-.1-.1-7-8.9C24 16.5 23.1 16 22 16H10z"/> - </g> - <g id="g8197"> - <circle id="circle8199" cx="51.9" cy="12.1" r="11.1" fill="#3389ff"/> - <path id="path8201" d="M51.9 24.2c-6.7 0-12.1-5.4-12.1-12.1S45.2 0 51.9 0 64 5.4 64 12.1s-5.4 12.1-12.1 12.1zm0-22.2c-5.6 0-10.1 4.5-10.1 10.1s4.5 10.1 10.1 10.1S62 17.7 62 12.1 57.5 2 51.9 2z" class="st7"/> - </g> - <g id="g8203"> - <path id="path8205" d="M57 13H47c-.6 0-1-.4-1-1s.4-1 1-1h10c.6 0 1 .4 1 1s-.4 1-1 1z" class="st7"/> - </g> - <g id="g8207"> - <path id="path8209" d="M52 18c-.6 0-1-.4-1-1V7c0-.6.4-1 1-1s1 .4 1 1v10c0 .6-.4 1-1 1z" class="st7"/> - </g> - <circle cx="25.1" cy="39.2" r="7.2" fill="none" stroke="#b5b5ea" stroke-miterlimit="10" stroke-width="2"/> - <path d="M30.9 43.6l12.4 9.3M41 51.2l3.3-4.4M38.3 48.1l1.5-2.1" class="st9"/> -</svg> \ No newline at end of file diff --git a/backend/src/Squidex/wwwroot/images/add-profile.svg b/backend/src/Squidex/wwwroot/images/add-profile.svg deleted file mode 100644 index e9b78a32b..000000000 --- a/backend/src/Squidex/wwwroot/images/add-profile.svg +++ /dev/null @@ -1,26 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" x="0" y="0" version="1.1" viewBox="0 0 64 64" xml:space="preserve"> - <style id="style2" type="text/css"> - .st7{fill:#fff} - </style> - <g id="g8143"> - <path id="path8145" fill="#b4bcc1" d="M11.8 16c.2.4.2.9.2 1.3V19h1v-1.6c0-.7-.1-1.4-.4-2l-.1-3.1c-.4-1.2-.3-2.5.4-3.5.6-1 1.6-1.6 2.7-1.7H23.2c2.4 0 4.6.9 6.3 2.6l4.7 4.7c2.1 2.1 4.8 3.2 7.7 3.2H50v-2h-8.1c-2.4 0-4.6-.9-6.3-2.6l-4.7-4.7C28.8 6.1 26.1 5 23.2 5h-7.8c-1.7.2-3.2 1.1-4.2 2.6-1 1.6-1.2 3.5-.6 5.3l1.2 3.1z"/> - </g> - <g id="g8147"> - <path id="path8149" fill="#d7d7f9" d="M3 24v-4.5C3 15.9 5.9 13 9.5 13h12.8c1.7 0 3.4.7 4.6 1.9l7.2 9.2c1.2 1.2 2.9 1.9 4.6 1.9h7.8C55.1 26 61 30.9 61 39.5v15c0 3.6-3.9 6.5-7.5 6.5h-44C5.9 61 3 58.1 3 54.5V24z"/> - <path id="path8151" fill="#2e3842" d="M53.5 62h-44C5.4 62 2 58.6 2 54.5v-35C2 15.4 5.4 12 9.5 12h12.8c2 0 3.9.8 5.3 2.2l.1.1 7.2 9.2c1 1 2.4 1.6 3.8 1.6h7.8C55.9 25 62 30.7 62 39.5v15c0 4.3-4.5 7.5-8.5 7.5zm-44-48c-3 0-5.5 2.5-5.5 5.5v35.1c0 3 2.5 5.5 5.5 5.5h44.1c2.9 0 6.5-2.4 6.5-5.5v-15C60 31.8 54.8 27 46.5 27h-7.8c-2 0-3.9-.8-5.3-2.2l-.1-.1-7.2-9.2c-1-1-2.4-1.6-3.8-1.6H9.5v.1z"/> - </g> - <g id="g8153"> - <path id="path8155" fill="#ededf9" d="M53 60H10c-3.8 0-6-2.2-6-6V20c0-3.8 2.2-6 6-6h12c2 0 3.6 1.2 4.7 2.3l.1.1 7 8.9c.6.5 2.1 1.7 4.5 1.5h7.3C54.7 26.9 60 31.3 60 39v15c0 3.6-2.8 6-7 6zM10 16c-2.7 0-4 1.3-4 4v34c0 2.7 1.3 4 4 4h43c2.3 0 5-1 5-4V39c0-8.8-7.9-10.1-12.5-10.1h-7.2c-2.2.1-4.4-.6-6-2.1l-.1-.1-7-8.9C24 16.5 23.1 16 22 16H10z"/> - </g> - <g id="g8197"> - <circle id="circle8199" cx="51.9" cy="12.1" r="11.1" fill="#3389ff"/> - <path id="path8201" d="M51.9 24.2c-6.7 0-12.1-5.4-12.1-12.1S45.2 0 51.9 0 64 5.4 64 12.1s-5.4 12.1-12.1 12.1zm0-22.2c-5.6 0-10.1 4.5-10.1 10.1s4.5 10.1 10.1 10.1S62 17.7 62 12.1 57.5 2 51.9 2z" class="st7"/> - </g> - <g id="g8203"> - <path id="path8205" d="M57 13H47c-.6 0-1-.4-1-1s.4-1 1-1h10c.6 0 1 .4 1 1s-.4 1-1 1z" class="st7"/> - </g> - <g id="g8207"> - <path id="path8209" d="M52 18c-.6 0-1-.4-1-1V7c0-.6.4-1 1-1s1 .4 1 1v10c0 .6-.4 1-1 1z" class="st7"/> - </g> - <path id="path36" fill="#b5b5ea" fill-opacity="1" stroke="#b5b5ea" stroke-dasharray="none" stroke-miterlimit="4" stroke-opacity="1" stroke-width=".5" d="M21.695 32.767c-3.123 0-5.67 2.547-5.67 5.667 0 1.56.588 3.48 1.55 5.105.466.787 1.04 1.514 1.701 2.065-1.409.179-2.892.223-4.081.759-1.893.852-3.423 2.247-4.087 4.235-.036.226 0 0-.036.214v.012a3.199 3.199 0 003.186 3.19h14.87a3.2 3.2 0 003.19-3.19l-.036-.222c-.66-1.998-2.188-3.394-4.081-4.245-1.19-.534-2.677-.58-4.087-.756.659-.552 1.233-1.277 1.697-2.063.962-1.625 1.551-3.544 1.551-5.105a5.678 5.678 0 00-5.667-5.667zm0 1.423a4.235 4.235 0 014.245 4.245c0 1.175-.519 2.973-1.352 4.381-.833 1.408-1.931 2.342-2.893 2.342-.962 0-2.06-.934-2.893-2.342-.832-1.407-1.354-3.206-1.354-4.38a4.238 4.238 0 014.247-4.246zm0 12.39c2.195 0 4.288.341 5.922 1.076 1.583.712 2.695 1.772 3.236 3.267-.058.93-.78 1.668-1.725 1.668h-14.87c-.94 0-1.662-.736-1.722-1.666.544-1.487 1.659-2.55 3.242-3.263 1.635-.736 3.728-1.082 5.916-1.082z"/> -</svg> \ No newline at end of file diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/AlwaysCreateClientCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AlwaysCreateClientCommandMiddlewareTests.cs similarity index 95% rename from backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/AlwaysCreateClientCommandMiddlewareTests.cs rename to backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AlwaysCreateClientCommandMiddlewareTests.cs index 2103be75b..2ceacc745 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/AlwaysCreateClientCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AlwaysCreateClientCommandMiddlewareTests.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Xunit; -namespace Squidex.Domain.Apps.Entities.Apps.Templates +namespace Squidex.Domain.Apps.Entities.Apps { public class AlwaysCreateClientCommandMiddlewareTests { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesClientTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesClientTests.cs new file mode 100644 index 000000000..7e64c9814 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesClientTests.cs @@ -0,0 +1,56 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using FakeItEasy; +using Xunit; + +namespace Squidex.Domain.Apps.Entities.Apps.Templates +{ + public class TemplatesClientTests + { + private readonly TemplatesClient sut; + + public TemplatesClientTests() + { + var httpClientFactory = A.Fake<IHttpClientFactory>(); + + A.CallTo(() => httpClientFactory.CreateClient(null)) + .Returns(new HttpClient()); + + sut = new TemplatesClient(httpClientFactory); + } + + [Fact] + public async Task Should_get_templates() + { + var templates = await sut.GetTemplatesAsync(); + + Assert.NotEmpty(templates); + } + + [Fact] + public async Task Should_get_details_from_templates() + { + var templates = await sut.GetTemplatesAsync(); + + foreach (var template in templates) + { + var details = await sut.GetDetailAsync(template.Name); + + Assert.NotNull(details); + } + } + + [Fact] + public async Task Should_return_null_details_if_not_found() + { + var details = await sut.GetDetailAsync("invalid"); + + Assert.Null(details); + } + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs deleted file mode 100644 index a71f7e064..000000000 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Templates/TemplatesTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using FakeItEasy; -using Squidex.Domain.Apps.Entities.Apps.Commands; -using Squidex.Domain.Apps.Entities.Schemas.Commands; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Commands; -using Xunit; - -namespace Squidex.Domain.Apps.Entities.Apps.Templates -{ - public class TemplatesTests - { - private readonly ICommandBus commandBus = A.Fake<ICommandBus>(); - - public static readonly IEnumerable<object[]> TemplateTests = new[] - { - new object[] { new CreateBlog() }, - new object[] { new CreateProfile() } - }; - - [Theory] - [MemberData(nameof(TemplateTests))] - public async Task Should_create_schemas(ITemplate template) - { - var appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - - var command = new CreateApp { AppId = appId.Id, Name = appId.Name, Template = template.Name }; - - var context = - new CommandContext(command, commandBus) - .Complete(); - - var sut = new TemplateCommandMiddleware(Enumerable.Repeat(template, 1)); - - await sut.HandleAsync(context); - - A.CallTo(() => commandBus.PublishAsync(A<CreateSchema>.That.Matches(x => x.AppId == appId))) - .MustHaveHappened(); - } - } -} diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index dfd745a5e..254ec9863 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -13,10 +13,12 @@ module.exports = { "project": "tsconfig.json" }, "plugins": [ + "deprecation", "eslint-plugin-import", "@typescript-eslint", ], "rules": { + "deprecation/deprecation": "warn", "@typescript-eslint/dot-notation": "off", "@typescript-eslint/indent": "off", "@typescript-eslint/lines-between-class-members": "off", @@ -107,12 +109,12 @@ module.exports = { "no-restricted-syntax": "off", "no-underscore-dangle": "off", "object-curly-newline": [ - "error", + "error", { - "ObjectExpression": { + "ObjectExpression": { "consistent": true }, - "ObjectPattern": { + "ObjectPattern": { "consistent": true }, "ImportDeclaration": "never", @@ -120,6 +122,13 @@ module.exports = { } ], "operator-linebreak": "off", - "prefer-destructuring": "off" + "prefer-destructuring": "off", + "sort-imports": [ + "error", + { + "ignoreCase": true, + "ignoreDeclarationSort": true + } + ], } }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8fc6038fa..5c7ba27eb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -93,6 +93,7 @@ "copy-webpack-plugin": "10.2.0", "eslint": "8.6.0", "eslint-config-airbnb-typescript": "16.1.0", + "eslint-plugin-deprecation": "^1.3.2", "eslint-plugin-import": "2.25.3", "eslint-plugin-jsx-a11y": "6.5.1", "eslint-webpack-plugin": "3.1.1", @@ -7556,6 +7557,21 @@ "node": ">=4" } }, + "node_modules/eslint-plugin-deprecation": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-1.3.2.tgz", + "integrity": "sha512-z93wbx9w7H/E3ogPw6AZMkkNJ6m51fTZRNZPNQqxQLmx+KKt7aLkMU9wN67s71i+VVHN4tLOZ3zT3QLbnlC0Mg==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "^5.0.0", + "tslib": "^2.3.1", + "tsutils": "^3.21.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0", + "typescript": "^3.7.5 || ^4.0.0" + } + }, "node_modules/eslint-plugin-import": { "version": "2.25.3", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", @@ -23673,6 +23689,17 @@ } } }, + "eslint-plugin-deprecation": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-1.3.2.tgz", + "integrity": "sha512-z93wbx9w7H/E3ogPw6AZMkkNJ6m51fTZRNZPNQqxQLmx+KKt7aLkMU9wN67s71i+VVHN4tLOZ3zT3QLbnlC0Mg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "^5.0.0", + "tslib": "^2.3.1", + "tsutils": "^3.21.0" + } + }, "eslint-plugin-import": { "version": "2.25.3", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 85b4546b6..7d7eb3223 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -98,6 +98,7 @@ "copy-webpack-plugin": "10.2.0", "eslint": "8.6.0", "eslint-config-airbnb-typescript": "16.1.0", + "eslint-plugin-deprecation": "^1.3.2", "eslint-plugin-import": "2.25.3", "eslint-plugin-jsx-a11y": "6.5.1", "eslint-webpack-plugin": "3.1.1", diff --git a/frontend/src/app/features/administration/guards/user-must-exist.guard.ts b/frontend/src/app/features/administration/guards/user-must-exist.guard.ts index 684db8666..8b85838db 100644 --- a/frontend/src/app/features/administration/guards/user-must-exist.guard.ts +++ b/frontend/src/app/features/administration/guards/user-must-exist.guard.ts @@ -7,7 +7,8 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; -import { Observable, map, tap } from 'rxjs'; +import { Observable } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; import { UsersState } from '@app/features/administration/internal'; import { allParams } from '@app/framework'; diff --git a/frontend/src/app/features/administration/services/event-consumers.service.spec.ts b/frontend/src/app/features/administration/services/event-consumers.service.spec.ts index e09bc936f..cb3e5eead 100644 --- a/frontend/src/app/features/administration/services/event-consumers.service.spec.ts +++ b/frontend/src/app/features/administration/services/event-consumers.service.spec.ts @@ -48,7 +48,7 @@ describe('EventConsumersService', () => { }); expect(eventConsumers!).toEqual( - new EventConsumersDto([ + new EventConsumersDto(2, [ createEventConsumer(12), createEventConsumer(13), ])); diff --git a/frontend/src/app/features/administration/services/event-consumers.service.ts b/frontend/src/app/features/administration/services/event-consumers.service.ts index 33bca9d7c..b7360d23e 100644 --- a/frontend/src/app/features/administration/services/event-consumers.service.ts +++ b/frontend/src/app/features/administration/services/event-consumers.service.ts @@ -9,16 +9,9 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { ApiUrlConfig, hasAnyLink, pretifyError, Resource, ResourceLinks } from '@app/shared'; +import { ApiUrlConfig, hasAnyLink, pretifyError, Resource, ResourceLinks, ResultSet } from '@app/shared'; -export class EventConsumersDto { - public readonly _links: ResourceLinks; - - constructor( - public readonly items: ReadonlyArray<EventConsumerDto>, links?: ResourceLinks, - ) { - this._links = links || {}; - } +export class EventConsumersDto extends ResultSet<EventConsumerDto> { } export class EventConsumerDto { @@ -55,11 +48,9 @@ export class EventConsumersService { public getEventConsumers(): Observable<EventConsumersDto> { const url = this.apiUrl.buildUrl('/api/event-consumers'); - return this.http.get<{ items: any[] } & Resource>(url).pipe( - map(({ items, _links }) => { - const eventConsumers = items.map(parseEventConsumer); - - return new EventConsumersDto(eventConsumers, _links); + return this.http.get<any>(url).pipe( + map(body => { + return parseEventConsumers(body); }), pretifyError('i18n:eventConsumers.loadFailed')); } @@ -101,9 +92,14 @@ export class EventConsumersService { } } +function parseEventConsumers(response: { items: any[] } & Resource) { + const items = response.items.map(parseEventConsumer); + + return new EventConsumersDto(items.length, items, response._links); +} + function parseEventConsumer(response: any): EventConsumerDto { - return new EventConsumerDto( - response._links, + return new EventConsumerDto(response._links, response.name, response.count, response.isStopped, diff --git a/frontend/src/app/features/administration/services/users.service.ts b/frontend/src/app/features/administration/services/users.service.ts index 75ca87049..38f9dcfe1 100644 --- a/frontend/src/app/features/administration/services/users.service.ts +++ b/frontend/src/app/features/administration/services/users.service.ts @@ -60,11 +60,9 @@ export class UsersService { public getUsers(take: number, skip: number, query?: string): Observable<UsersDto> { const url = this.apiUrl.buildUrl(`api/user-management?take=${take}&skip=${skip}&query=${query || ''}`); - return this.http.get<{ total: number; items: any[] } & Resource>(url).pipe( - map(({ total, items, _links }) => { - const users = items.map(parseUser); - - return new UsersDto(total, users, _links); + return this.http.get<any>(url).pipe( + map(body => { + return parseUsers(body); }), pretifyError('i18n:users.loadFailed')); } @@ -135,6 +133,12 @@ export class UsersService { } } +function parseUsers(response: { items: any[]; total: number } & Resource) { + const items = response.items.map(parseUser); + + return new UsersDto(response.total, items, response._links); +} + function parseUser(response: any) { return new UserDto( response._links, diff --git a/frontend/src/app/features/administration/state/event-consumers.state.spec.ts b/frontend/src/app/features/administration/state/event-consumers.state.spec.ts index 8ccd67098..f2cef1330 100644 --- a/frontend/src/app/features/administration/state/event-consumers.state.spec.ts +++ b/frontend/src/app/features/administration/state/event-consumers.state.spec.ts @@ -35,7 +35,7 @@ describe('EventConsumersState', () => { describe('Loading', () => { it('should load event consumers', () => { eventConsumersService.setup(x => x.getEventConsumers()) - .returns(() => of(new EventConsumersDto([eventConsumer1, eventConsumer2]))).verifiable(); + .returns(() => of(new EventConsumersDto(2, [eventConsumer1, eventConsumer2], {}))).verifiable(); eventConsumersState.load().subscribe(); @@ -57,7 +57,7 @@ describe('EventConsumersState', () => { it('should show notification on load if reload is true', () => { eventConsumersService.setup(x => x.getEventConsumers()) - .returns(() => of(new EventConsumersDto([eventConsumer1, eventConsumer2]))).verifiable(); + .returns(() => of(new EventConsumersDto(2, [eventConsumer1, eventConsumer2], {}))).verifiable(); eventConsumersState.load(true).subscribe(); @@ -81,7 +81,7 @@ describe('EventConsumersState', () => { describe('Updates', () => { beforeEach(() => { eventConsumersService.setup(x => x.getEventConsumers()) - .returns(() => of(new EventConsumersDto([eventConsumer1, eventConsumer2]))).verifiable(); + .returns(() => of(new EventConsumersDto(2, [eventConsumer1, eventConsumer2], {}))).verifiable(); eventConsumersState.load().subscribe(); }); diff --git a/frontend/src/app/features/administration/state/users.forms.ts b/frontend/src/app/features/administration/state/users.forms.ts index 51a19d479..151275ab4 100644 --- a/frontend/src/app/features/administration/state/users.forms.ts +++ b/frontend/src/app/features/administration/state/users.forms.ts @@ -6,7 +6,7 @@ */ import { FormControl, Validators } from '@angular/forms'; -import { Form, ExtendedFormGroup, ValidatorsEx } from '@app/shared'; +import { ExtendedFormGroup, Form, ValidatorsEx } from '@app/shared'; import { UpdateUserDto, UserDto } from './../services/users.service'; export class UserForm extends Form<ExtendedFormGroup, UpdateUserDto, UserDto> { diff --git a/frontend/src/app/features/api/pages/graphql/graphql-page.component.ts b/frontend/src/app/features/api/pages/graphql/graphql-page.component.ts index fefb5c54e..4c5674e26 100644 --- a/frontend/src/app/features/api/pages/graphql/graphql-page.component.ts +++ b/frontend/src/app/features/api/pages/graphql/graphql-page.component.ts @@ -9,7 +9,7 @@ import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core'; import GraphiQL from 'graphiql'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { of } from 'rxjs'; +import { firstValueFrom, of } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { AppsState, GraphQlService } from '@app/shared'; @@ -32,7 +32,7 @@ export class GraphQLPageComponent implements AfterViewInit { ReactDOM.render( React.createElement(GraphiQL, { fetcher: (params: any) => { - return this.request(params); + return firstValueFrom(this.request(params)); }, }), this.graphiQLContainer.nativeElement, @@ -41,7 +41,6 @@ export class GraphQLPageComponent implements AfterViewInit { private request(params: any) { return this.graphQlService.query(this.appsState.appName, params).pipe( - catchError(response => of(response.error))) - .toPromise(); + catchError(response => of(response.error))); } } diff --git a/frontend/src/app/features/apps/pages/apps-page.component.html b/frontend/src/app/features/apps/pages/apps-page.component.html index 8fa9f0cd2..0a2f4a3bb 100644 --- a/frontend/src/app/features/apps/pages/apps-page.component.html +++ b/frontend/src/app/features/apps/pages/apps-page.component.html @@ -22,7 +22,7 @@ </ng-container> <div class="apps-section" *ngIf="(uiState.settings | async)?.canCreateApps"> - <div class="card card-template card-href" (click)="createNewApp('')"> + <div class="card card-template card-href" (click)="createNewApp()"> <div class="card-body"> <div class="card-image"> <img src="./images/add-app.svg"> @@ -35,38 +35,6 @@ </sqx-form-hint> </div> </div> - - <div class="card card-template card-href" (click)="createNewApp('Blog')"> - <div class="card-body"> - <div class="card-image"> - <img src="./images/add-blog.svg"> - </div> - - <h3 class="card-title">{{ 'apps.createBlogApp' | sqxTranslate }}</h3> - - <sqx-form-hint> - {{ 'apps.createBlogAppDescription' | sqxTranslate }} - <br /> - {{ 'common.sampleCodeLabel' | sqxTranslate }} <a href="https://github.com/Squidex/squidex-samples" sqxStopClick sqxExternalLink>{{ 'common.github' | sqxTranslate }}</a> - </sqx-form-hint> - </div> - </div> - - <div class="card card-template card-href" (click)="createNewApp('Profile')"> - <div class="card-body"> - <div class="card-image"> - <img src="./images/add-profile.svg"> - </div> - - <h3 class="card-title">{{ 'apps.createProfileApp' | sqxTranslate }}</h3> - - <sqx-form-hint> - {{ 'apps.createProfileAppDescription' | sqxTranslate }} - <br /> - {{ 'common.sampleCodeLabel' | sqxTranslate }} <a href="https://github.com/Squidex/squidex-samples" sqxStopClick sqxExternalLink>{{ 'common.github' | sqxTranslate }}</a> - </sqx-form-hint> - </div> - </div> </div> <div *ngIf="info" class="apps-section"> @@ -75,7 +43,7 @@ </div> <ng-container *sqxModal="addAppDialog"> - <sqx-app-form [template]="addAppTemplate" (complete)="addAppDialog.hide()"></sqx-app-form> + <sqx-app-form (complete)="addAppDialog.hide()"></sqx-app-form> </ng-container> <ng-container *sqxModal="onboardingDialog"> diff --git a/frontend/src/app/features/apps/pages/apps-page.component.ts b/frontend/src/app/features/apps/pages/apps-page.component.ts index 535080eda..2259bc1d8 100644 --- a/frontend/src/app/features/apps/pages/apps-page.component.ts +++ b/frontend/src/app/features/apps/pages/apps-page.component.ts @@ -17,7 +17,6 @@ import { Settings } from '@app/shared/state/settings'; }) export class AppsPageComponent implements OnInit { public addAppDialog = new DialogModel(); - public addAppTemplate = ''; public onboardingDialog = new DialogModel(); @@ -66,8 +65,7 @@ export class AppsPageComponent implements OnInit { }); } - public createNewApp(template: string) { - this.addAppTemplate = template; + public createNewApp() { this.addAppDialog.show(); } diff --git a/frontend/src/app/features/content/pages/content/content-page.component.ts b/frontend/src/app/features/content/pages/content/content-page.component.ts index bb7c5d29c..f20f1b628 100644 --- a/frontend/src/app/features/content/pages/content/content-page.component.ts +++ b/frontend/src/app/features/content/pages/content/content-page.component.ts @@ -9,7 +9,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Observable, of } from 'rxjs'; import { filter, map, tap } from 'rxjs/operators'; -import { ApiUrlConfig, AppLanguageDto, AppsState, AuthService, AutoSaveKey, AutoSaveService, CanComponentDeactivate, ContentDto, ResolveContents, ContentsState, defined, DialogService, EditContentForm, LanguagesState, ModalModel, ResourceOwner, SchemaDto, SchemasState, TempService, ToolbarService, Types, Version, ResolveAssets } from '@app/shared'; +import { ApiUrlConfig, AppLanguageDto, AppsState, AuthService, AutoSaveKey, AutoSaveService, CanComponentDeactivate, ContentDto, ContentsState, defined, DialogService, EditContentForm, LanguagesState, ModalModel, ResolveAssets, ResolveContents, ResourceOwner, SchemaDto, SchemasState, TempService, ToolbarService, Types, Version } from '@app/shared'; @Component({ selector: 'sqx-content-page', diff --git a/frontend/src/app/features/content/shared/references/reference-dropdown.component.ts b/frontend/src/app/features/content/shared/references/reference-dropdown.component.ts index 487c2f20e..5be8f8870 100644 --- a/frontend/src/app/features/content/shared/references/reference-dropdown.component.ts +++ b/frontend/src/app/features/content/shared/references/reference-dropdown.component.ts @@ -9,7 +9,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Inpu import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Observable } from 'rxjs'; import { ContentsDto } from '@app/shared'; -import { ContentDto, ResolveContents, getContentValue, LanguageDto, LocalizerService, StatefulControlComponent, Types, value$ } from '@app/shared/internal'; +import { ContentDto, getContentValue, LanguageDto, LocalizerService, ResolveContents, StatefulControlComponent, Types, value$ } from '@app/shared/internal'; export const SQX_REFERENCE_DROPDOWN_CONTROL_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReferenceDropdownComponent), multi: true, diff --git a/frontend/src/app/features/content/shared/references/references-editor.component.ts b/frontend/src/app/features/content/shared/references/references-editor.component.ts index 2faf9624a..fd82f43e9 100644 --- a/frontend/src/app/features/content/shared/references/references-editor.component.ts +++ b/frontend/src/app/features/content/shared/references/references-editor.component.ts @@ -8,7 +8,7 @@ import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { AppLanguageDto, ContentDto, ResolveContents, DialogModel, sorted, StatefulControlComponent, Types } from '@app/shared'; +import { AppLanguageDto, ContentDto, DialogModel, ResolveContents, sorted, StatefulControlComponent, Types } from '@app/shared'; export const SQX_REFERENCES_EDITOR_CONTROL_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReferencesEditorComponent), multi: true, diff --git a/frontend/src/app/features/content/shared/references/references-tags.component.ts b/frontend/src/app/features/content/shared/references/references-tags.component.ts index 1421942e0..9adb51356 100644 --- a/frontend/src/app/features/content/shared/references/references-tags.component.ts +++ b/frontend/src/app/features/content/shared/references/references-tags.component.ts @@ -9,7 +9,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Inpu import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Observable } from 'rxjs'; import { Types } from '@app/framework'; -import { ContentDto, ContentsDto, ResolveContents, LanguageDto, LocalizerService, StatefulControlComponent } from '@app/shared/internal'; +import { ContentDto, ContentsDto, LanguageDto, LocalizerService, ResolveContents, StatefulControlComponent } from '@app/shared/internal'; import { ReferencesTagsConverter } from './references-tag-converter'; export const SQX_REFERENCES_TAGS_CONTROL_VALUE_ACCESSOR: any = { diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.ts index eae76b593..33fc7ca74 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.ts @@ -7,7 +7,7 @@ import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { BooleanFieldPropertiesDto, BOOLEAN_FIELD_EDITORS, FieldDto } from '@app/shared'; +import { BOOLEAN_FIELD_EDITORS, BooleanFieldPropertiesDto, FieldDto } from '@app/shared'; @Component({ selector: 'sqx-boolean-ui[field][fieldForm][properties]', diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.ts index dbb5f06f2..f9dbd8aee 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.ts @@ -7,7 +7,7 @@ import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { DateTimeFieldPropertiesDto, DATETIME_FIELD_EDITORS, FieldDto, FloatConverter } from '@app/shared'; +import { DATETIME_FIELD_EDITORS, DateTimeFieldPropertiesDto, FieldDto, FloatConverter } from '@app/shared'; @Component({ selector: 'sqx-date-time-ui[field][fieldForm][properties]', diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.ts index 7c0e4cb74..30e73d8cc 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.ts @@ -8,7 +8,7 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Observable } from 'rxjs'; -import { FieldDto, FloatConverter, NumberFieldPropertiesDto, NUMBER_FIELD_EDITORS, ResourceOwner, valueProjection$ } from '@app/shared'; +import { FieldDto, FloatConverter, NUMBER_FIELD_EDITORS, NumberFieldPropertiesDto, ResourceOwner, valueProjection$ } from '@app/shared'; @Component({ selector: 'sqx-number-ui[field][fieldForm][properties]', diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.ts index 08753919a..4eda12f88 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.ts @@ -7,7 +7,7 @@ import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { FieldDto, ReferencesFieldPropertiesDto, REFERENCES_FIELD_EDITORS } from '@app/shared'; +import { FieldDto, REFERENCES_FIELD_EDITORS, ReferencesFieldPropertiesDto } from '@app/shared'; @Component({ selector: 'sqx-references-ui[field][fieldForm][properties]', diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.ts index 70aac478f..85713c746 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.ts @@ -8,7 +8,7 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Observable } from 'rxjs'; -import { FieldDto, ResourceOwner, StringFieldPropertiesDto, STRING_FIELD_EDITORS, valueProjection$ } from '@app/shared'; +import { FieldDto, ResourceOwner, STRING_FIELD_EDITORS, StringFieldPropertiesDto, valueProjection$ } from '@app/shared'; @Component({ selector: 'sqx-string-ui[field][fieldForm][properties]', diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.ts index 545f9b2dd..e0839bf83 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.ts @@ -8,7 +8,7 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Observable } from 'rxjs'; -import { AppSettingsDto, FieldDto, hasNoValue$, hasValue$, LanguageDto, ModalModel, PatternDto, ResourceOwner, RootFieldDto, SchemaDto, StringFieldPropertiesDto, STRING_CONTENT_TYPES, Types, value$ } from '@app/shared'; +import { AppSettingsDto, FieldDto, hasNoValue$, hasValue$, LanguageDto, ModalModel, PatternDto, ResourceOwner, RootFieldDto, SchemaDto, STRING_CONTENT_TYPES, StringFieldPropertiesDto, Types, value$ } from '@app/shared'; @Component({ selector: 'sqx-string-validation[field][fieldForm][languages][properties][schema][settings]', diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.ts index 4a3d6e8e0..1e1946e1d 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.ts @@ -7,7 +7,7 @@ import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { FieldDto, TagsFieldPropertiesDto, TAGS_FIELD_EDITORS } from '@app/shared'; +import { FieldDto, TAGS_FIELD_EDITORS, TagsFieldPropertiesDto } from '@app/shared'; @Component({ selector: 'sqx-tags-ui[field][fieldForm][properties]', diff --git a/frontend/src/app/features/settings/declarations.ts b/frontend/src/app/features/settings/declarations.ts index 67e99348e..576936dd7 100644 --- a/frontend/src/app/features/settings/declarations.ts +++ b/frontend/src/app/features/settings/declarations.ts @@ -26,6 +26,8 @@ export * from './pages/roles/role-add-form.component'; export * from './pages/roles/role.component'; export * from './pages/roles/roles-page.component'; export * from './pages/settings/settings-page.component'; +export * from './pages/templates/template.component'; +export * from './pages/templates/templates-page.component'; export * from './pages/workflows/workflow-add-form.component'; export * from './pages/workflows/workflow-diagram.component'; export * from './pages/workflows/workflow-step.component'; diff --git a/frontend/src/app/features/settings/module.ts b/frontend/src/app/features/settings/module.ts index 751ba36c9..5bff29a79 100644 --- a/frontend/src/app/features/settings/module.ts +++ b/frontend/src/app/features/settings/module.ts @@ -8,9 +8,7 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HelpComponent, HistoryComponent, SqxFrameworkModule, SqxSharedModule } from '@app/shared'; -import { AssetScriptsPageComponent, BackupComponent, BackupsPageComponent, ClientAddFormComponent, ClientComponent, ClientConnectFormComponent, ClientsPageComponent, ContributorAddFormComponent, ContributorComponent, ContributorsPageComponent, ImportContributorsDialogComponent, LanguageAddFormComponent, LanguageComponent, LanguagesPageComponent, MorePageComponent, PlanComponent, PlansPageComponent, RoleAddFormComponent, RoleComponent, RolesPageComponent, SettingsAreaComponent, WorkflowAddFormComponent, WorkflowComponent, WorkflowsPageComponent, WorkflowStepComponent, WorkflowTransitionComponent } from './declarations'; -import { SettingsPageComponent } from './pages/settings/settings-page.component'; -import { WorkflowDiagramComponent } from './pages/workflows/workflow-diagram.component'; +import { AssetScriptsPageComponent, BackupComponent, BackupsPageComponent, ClientAddFormComponent, ClientComponent, ClientConnectFormComponent, ClientsPageComponent, ContributorAddFormComponent, ContributorComponent, ContributorsPageComponent, ImportContributorsDialogComponent, LanguageAddFormComponent, LanguageComponent, LanguagesPageComponent, MorePageComponent, PlanComponent, PlansPageComponent, RoleAddFormComponent, RoleComponent, RolesPageComponent, SettingsAreaComponent, SettingsPageComponent, TemplateComponent, TemplatesPageComponent, WorkflowAddFormComponent, WorkflowComponent, WorkflowDiagramComponent, WorkflowsPageComponent, WorkflowStepComponent, WorkflowTransitionComponent } from './declarations'; const routes: Routes = [ { @@ -98,6 +96,10 @@ const routes: Routes = [ path: 'settings', component: SettingsPageComponent, }, + { + path: 'templates', + component: TemplatesPageComponent, + }, { path: 'plans', component: PlansPageComponent, @@ -188,8 +190,10 @@ const routes: Routes = [ RoleAddFormComponent, RoleComponent, RolesPageComponent, - SettingsPageComponent, SettingsAreaComponent, + SettingsPageComponent, + TemplateComponent, + TemplatesPageComponent, WorkflowAddFormComponent, WorkflowComponent, WorkflowDiagramComponent, diff --git a/frontend/src/app/features/settings/pages/templates/template.component.html b/frontend/src/app/features/settings/pages/templates/template.component.html new file mode 100644 index 000000000..90680d9db --- /dev/null +++ b/frontend/src/app/features/settings/pages/templates/template.component.html @@ -0,0 +1,26 @@ +<div class="table-items-row table-items-row-expandable"> + <div class="table-items-row-summary row gx-2 align-items-center"> + <div class="col"> + {{template.title}} + + <sqx-form-hint>{{template.description}}</sqx-form-hint> + </div> + <div class="col-auto"> + <div class="float-end"> + <button type="button" class="btn btn-outline-secondary btn-expand me-1" [class.expanded]="isExpanded" (click)="toggleExpanded()"> + <i class="icon-download"></i> + </button> + </div> + </div> + </div> + + <div class="table-items-row-details" *ngIf="isExpanded"> + <div class="table-items-row-details-tabs clearfix"> + <h4>{{ 'common.details' | sqxTranslate }}</h4> + </div> + + <div class="table-items-row-details-tab"> + <div class="help" [innerHTML]="details | async | sqxMarkdown | sqxSafeHtml"></div> + </div> + </div> +</div> \ No newline at end of file diff --git a/frontend/src/app/features/settings/pages/templates/template.component.scss b/frontend/src/app/features/settings/pages/templates/template.component.scss new file mode 100644 index 000000000..86214aa61 --- /dev/null +++ b/frontend/src/app/features/settings/pages/templates/template.component.scss @@ -0,0 +1,17 @@ +@import 'mixins'; +@import 'vars'; + +h4 { + font-size: 1rem; + font-weight: 500; + margin: 0; + margin-top: .5rem; +} + +.help { + ::ng-deep { + h1 { + display: none; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/features/settings/pages/templates/template.component.ts b/frontend/src/app/features/settings/pages/templates/template.component.ts new file mode 100644 index 000000000..6b5f5ee3a --- /dev/null +++ b/frontend/src/app/features/settings/pages/templates/template.component.ts @@ -0,0 +1,57 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; +import { map, Observable, shareReplay } from 'rxjs'; +import { AppsState, ClientsState, TemplateDetailsDto, TemplateDto, TemplatesService } from '@app/shared'; + +@Component({ + selector: 'sqx-template[template]', + styleUrls: ['./template.component.scss'], + templateUrl: './template.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TemplateComponent implements OnChanges { + @Input() + public template!: TemplateDto; + + public isExpanded = false; + + public details?: Observable<string>; + + constructor( + private readonly clientsState: ClientsState, + private readonly appsState: AppsState, + private readonly templatesService: TemplatesService, + ) { + } + + public ngOnChanges() { + this.details = this.templatesService.getTemplate(this.template).pipe(map(x => this.buildDetails(x)), shareReplay(1)); + } + + public toggleExpanded() { + this.isExpanded = !this.isExpanded; + } + + private buildDetails(dto: TemplateDetailsDto) { + const app = this.appsState.appName; + + let details = dto.details.replace(/<APP>/g, app); + + const client = this.clientsState.snapshot.clients[0]; + + if (client) { + const clientId = `${app}:${client.id}`; + + details = details.replace(/\<CLIENT_ID>/g, clientId); + details = details.replace(/\<CLIENT_SECRET>/g, client.secret); + } + + return details; + } +} diff --git a/frontend/src/app/features/settings/pages/templates/templates-page.component.html b/frontend/src/app/features/settings/pages/templates/templates-page.component.html new file mode 100644 index 000000000..fec31a9af --- /dev/null +++ b/frontend/src/app/features/settings/pages/templates/templates-page.component.html @@ -0,0 +1,25 @@ +<sqx-title message="i18n:common.templates"></sqx-title> + +<sqx-layout layout="main" titleText="i18n:common.templates" titleIcon="templates" [innerWidth]="50" [hideSidebar]="true"> + <ng-container menu> + <button type="button" class="btn btn-text-secondary me-2" (click)="reload()" title="i18n:templates.refreshTooltip" shortcut="CTRL + B"> + <i class="icon-reset"></i> {{ 'common.refresh' | sqxTranslate }} + </button> + </ng-container> + + <ng-container> + <sqx-list-view innerWidth="50rem" [isLoading]="templatesState.isLoading | async"> + <sqx-form-alert [light]="true"> + <div class="help" [innerHTML]="'templates.cliHint' | sqxTranslate | sqxMarkdownInline | sqxSafeHtml"></div> + </sqx-form-alert> + + <ng-container *ngIf="(templatesState.isLoaded | async) && (templatesState.templates | async); let templates"> + <sqx-template *ngFor="let template of templates; trackBy: trackByTemplate" + [template]="template"> + </sqx-template> + </ng-container> + </sqx-list-view> + </ng-container> +</sqx-layout> + +<router-outlet></router-outlet> diff --git a/frontend/src/app/features/settings/pages/templates/templates-page.component.scss b/frontend/src/app/features/settings/pages/templates/templates-page.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/features/settings/pages/templates/templates-page.component.ts b/frontend/src/app/features/settings/pages/templates/templates-page.component.ts new file mode 100644 index 000000000..53ece4890 --- /dev/null +++ b/frontend/src/app/features/settings/pages/templates/templates-page.component.ts @@ -0,0 +1,37 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { Component, OnInit } from '@angular/core'; +import { ClientsState, ResourceOwner, TemplateDto, TemplatesState } from '@app/shared'; + +@Component({ + selector: 'sqx-templates-page', + styleUrls: ['./templates-page.component.scss'], + templateUrl: './templates-page.component.html', +}) +export class TemplatesPageComponent extends ResourceOwner implements OnInit { + constructor( + public readonly clientsState: ClientsState, + public readonly templatesState: TemplatesState, + ) { + super(); + } + + public ngOnInit() { + this.clientsState.load(); + + this.templatesState.load(); + } + + public reload() { + this.templatesState.load(true); + } + + public trackByTemplate(_index: number, item: TemplateDto) { + return item.name; + } +} diff --git a/frontend/src/app/features/settings/pages/workflows/workflow.component.ts b/frontend/src/app/features/settings/pages/workflows/workflow.component.ts index 1ccc82ed7..4318d65fa 100644 --- a/frontend/src/app/features/settings/pages/workflows/workflow.component.ts +++ b/frontend/src/app/features/settings/pages/workflows/workflow.component.ts @@ -55,10 +55,13 @@ export class WorkflowComponent implements OnChanges { } this.workflowsState.update(this.workflow) - .subscribe(() => { - this.error = null; - }, (error: ErrorDto) => { - this.error = error; + .subscribe({ + next: () => { + this.error = null; + }, + error: (error: ErrorDto) => { + this.error = error; + }, }); } diff --git a/frontend/src/app/features/settings/settings-area.component.html b/frontend/src/app/features/settings/settings-area.component.html index 90627450b..954f8bafb 100644 --- a/frontend/src/app/features/settings/settings-area.component.html +++ b/frontend/src/app/features/settings/settings-area.component.html @@ -49,6 +49,11 @@ <li class="nav-item nav-heading"> {{ 'common.more' | sqxTranslate }} </li> + <li class="nav-item" *ngIf="app.canReadClients"> + <a class="nav-link" routerLink="templates" routerLinkActive="active"> + <i class="icon-download"></i> {{ 'common.templates' | sqxTranslate }} + </a> + </li> <li class="nav-item" *ngIf="app.canReadBackups"> <a class="nav-link" routerLink="backups" routerLinkActive="active"> <i class="icon-backups"></i> {{ 'common.backups' | sqxTranslate }} diff --git a/frontend/src/app/framework/angular/forms/confirm-click.directive.ts b/frontend/src/app/framework/angular/forms/confirm-click.directive.ts index 41b8899c6..dacc452ad 100644 --- a/frontend/src/app/framework/angular/forms/confirm-click.directive.ts +++ b/frontend/src/app/framework/angular/forms/confirm-click.directive.ts @@ -6,8 +6,7 @@ */ import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core'; -import { Subscriber } from 'rxjs'; -import { take } from 'rxjs/operators'; +import { Subscriber, take } from 'rxjs'; import { DialogService, Types } from '@app/framework/internal'; @Directive({ @@ -44,6 +43,7 @@ export class ConfirmClickDirective { this.confirmTitle.length > 0 && this.confirmText && this.confirmText.length > 0) { + // eslint-disable-next-line deprecation/deprecation const destinations = this.clickConfirmed.observers?.map(x => (x as Subscriber<any>)['destination']) || []; this.beforeClick.emit(); diff --git a/frontend/src/app/framework/angular/forms/copy.directive.ts b/frontend/src/app/framework/angular/forms/copy.directive.ts index b308e7ad1..fc92b6d8f 100644 --- a/frontend/src/app/framework/angular/forms/copy.directive.ts +++ b/frontend/src/app/framework/angular/forms/copy.directive.ts @@ -63,6 +63,7 @@ export class CopyDirective { private copy() { try { + // eslint-disable-next-line deprecation/deprecation document.execCommand('copy'); this.dialogs.notifyInfo('i18n:common.clipboardAdded'); diff --git a/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts b/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts index 9378fe87f..812400b62 100644 --- a/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts +++ b/frontend/src/app/framework/angular/forms/editors/code-editor.component.ts @@ -7,8 +7,7 @@ import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Subject } from 'rxjs'; -import { debounceTime } from 'rxjs/operators'; +import { debounceTime, Subject } from 'rxjs'; import { ResourceLoaderService, StatefulControlComponent, Types } from '@app/framework/internal'; import { FocusComponent } from './../forms-helper'; diff --git a/frontend/src/app/framework/angular/http/caching.interceptor.ts b/frontend/src/app/framework/angular/http/caching.interceptor.ts index 63aae1adb..a862f45ab 100644 --- a/frontend/src/app/framework/angular/http/caching.interceptor.ts +++ b/frontend/src/app/framework/angular/http/caching.interceptor.ts @@ -7,8 +7,7 @@ import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Observable, of, throwError } from 'rxjs'; -import { catchError, tap } from 'rxjs/operators'; +import { catchError, Observable, of, tap, throwError } from 'rxjs'; import { Types } from '@app/framework/internal'; @Injectable() diff --git a/frontend/src/app/framework/angular/http/http-extensions.ts b/frontend/src/app/framework/angular/http/http-extensions.ts index fb6876fe0..efac5188e 100644 --- a/frontend/src/app/framework/angular/http/http-extensions.ts +++ b/frontend/src/app/framework/angular/http/http-extensions.ts @@ -8,8 +8,7 @@ /* eslint-disable no-inner-declarations */ import { HttpClient, HttpErrorResponse, HttpEvent, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http'; -import { Observable, throwError } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; +import { catchError, map, Observable, throwError } from 'rxjs'; import { ErrorDto, Types, Version, Versioned } from '@app/framework/internal'; export module HTTP { diff --git a/frontend/src/app/framework/angular/http/loading.interceptor.ts b/frontend/src/app/framework/angular/http/loading.interceptor.ts index 881a17beb..1be5033d2 100644 --- a/frontend/src/app/framework/angular/http/loading.interceptor.ts +++ b/frontend/src/app/framework/angular/http/loading.interceptor.ts @@ -7,8 +7,7 @@ import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { finalize } from 'rxjs/operators'; +import { finalize, Observable } from 'rxjs'; import { LoadingService, MathHelper } from '@app/framework/internal'; @Injectable() diff --git a/frontend/src/app/framework/angular/layout.component.ts b/frontend/src/app/framework/angular/layout.component.ts index be8166e8b..015894e79 100644 --- a/frontend/src/app/framework/angular/layout.component.ts +++ b/frontend/src/app/framework/angular/layout.component.ts @@ -9,7 +9,7 @@ import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core'; import { ActivatedRoute, NavigationEnd, QueryParamsHandling, Router } from '@angular/router'; -import { filter, map, startWith } from 'rxjs/operators'; +import { filter, map, startWith } from 'rxjs'; import { LayoutContainerDirective } from './layout-container.directive'; @Component({ diff --git a/frontend/src/app/framework/angular/stateful.component.ts b/frontend/src/app/framework/angular/stateful.component.ts index abaea35fc..e8bff4405 100644 --- a/frontend/src/app/framework/angular/stateful.component.ts +++ b/frontend/src/app/framework/angular/stateful.component.ts @@ -7,8 +7,7 @@ import { ChangeDetectorRef, Directive, OnDestroy } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; -import { EMPTY, Observable, Subscription } from 'rxjs'; -import { catchError, skip } from 'rxjs/operators'; +import { catchError, EMPTY, Observable, skip, Subscription } from 'rxjs'; import { State } from './../state'; import { Types } from './../utils/types'; diff --git a/frontend/src/app/framework/services/analytics.service.ts b/frontend/src/app/framework/services/analytics.service.ts index 46388c1f6..61094be24 100644 --- a/frontend/src/app/framework/services/analytics.service.ts +++ b/frontend/src/app/framework/services/analytics.service.ts @@ -7,7 +7,7 @@ import { Injectable } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; -import { filter } from 'rxjs/operators'; +import { filter } from 'rxjs'; import { UIOptions } from './../configurations'; import { Types } from './../utils/types'; import { ResourceLoaderService } from './resource-loader.service'; diff --git a/frontend/src/app/framework/services/dialog.service.ts b/frontend/src/app/framework/services/dialog.service.ts index 8eebd5f59..c23130f03 100644 --- a/frontend/src/app/framework/services/dialog.service.ts +++ b/frontend/src/app/framework/services/dialog.service.ts @@ -5,6 +5,8 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ +/* eslint-disable deprecation/deprecation */ + import { Injectable } from '@angular/core'; import { Observable, ReplaySubject, Subject, throwError } from 'rxjs'; import { ErrorDto } from './../utils/error'; diff --git a/frontend/src/app/framework/services/loading.service.ts b/frontend/src/app/framework/services/loading.service.ts index bf31c31f4..9cfd9b4ae 100644 --- a/frontend/src/app/framework/services/loading.service.ts +++ b/frontend/src/app/framework/services/loading.service.ts @@ -7,8 +7,7 @@ import { Injectable, OnDestroy } from '@angular/core'; import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { BehaviorSubject, map, Observable, Subscription } from 'rxjs'; import { Types } from './../utils/types'; @Injectable() diff --git a/frontend/src/app/framework/services/message-bus.service.ts b/frontend/src/app/framework/services/message-bus.service.ts index 108f4dee2..a6d8d3c93 100644 --- a/frontend/src/app/framework/services/message-bus.service.ts +++ b/frontend/src/app/framework/services/message-bus.service.ts @@ -6,8 +6,7 @@ */ import { Injectable } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; +import { filter, map, Observable, Subject } from 'rxjs'; interface Message { // The target. diff --git a/frontend/src/app/framework/utils/keys.ts b/frontend/src/app/framework/utils/keys.ts index 1839bb9c1..ae79ed572 100644 --- a/frontend/src/app/framework/utils/keys.ts +++ b/frontend/src/app/framework/utils/keys.ts @@ -5,6 +5,8 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ +/* eslint-disable deprecation/deprecation */ + export module Keys { const ALT = 18; const COMMA = 188; diff --git a/frontend/src/app/framework/utils/rxjs-extensions.ts b/frontend/src/app/framework/utils/rxjs-extensions.ts index b0b0726fe..05a485c29 100644 --- a/frontend/src/app/framework/utils/rxjs-extensions.ts +++ b/frontend/src/app/framework/utils/rxjs-extensions.ts @@ -6,7 +6,8 @@ */ import { EMPTY, Observable, ReplaySubject, throwError } from 'rxjs'; -import { catchError, debounceTime, distinctUntilChanged, filter, map, onErrorResumeNext, share, switchMap } from 'rxjs/operators'; +import { catchError, debounceTime, distinctUntilChanged, filter, map, share, switchMap } from 'rxjs/operators'; +import { onErrorResumeNext } from 'rxjs/operators'; import { DialogService } from './../services/dialog.service'; import { Version, versioned, Versioned } from './version'; diff --git a/frontend/src/app/shared/components/app-form.component.html b/frontend/src/app/shared/components/app-form.component.html index bda3f6318..570860f9c 100644 --- a/frontend/src/app/shared/components/app-form.component.html +++ b/frontend/src/app/shared/components/app-form.component.html @@ -1,13 +1,7 @@ <form [formGroup]="createForm.form" (ngSubmit)="createApp()"> <sqx-modal-dialog (close)="emitComplete()"> <ng-container title> - <ng-container *ngIf="template; else noTemplate"> - {{ 'apps.createWithTemplate' | sqxTranslate: { template: template } }} - </ng-container> - - <ng-template #noTemplate> - {{ 'apps.create' | sqxTranslate }} - </ng-template> + {{ 'apps.create' | sqxTranslate }} </ng-container> <ng-container content> diff --git a/frontend/src/app/shared/components/app-form.component.ts b/frontend/src/app/shared/components/app-form.component.ts index 5881faf45..3ae0bc779 100644 --- a/frontend/src/app/shared/components/app-form.component.ts +++ b/frontend/src/app/shared/components/app-form.component.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Output } from '@angular/core'; import { ApiUrlConfig, AppsState, CreateAppForm } from '@app/shared/internal'; @Component({ @@ -18,9 +18,6 @@ export class AppFormComponent { @Output() public complete = new EventEmitter(); - @Input() - public template = ''; - public createForm = new CreateAppForm(); constructor( @@ -37,9 +34,7 @@ export class AppFormComponent { const value = this.createForm.submit(); if (value) { - const request = { ...value, template: this.template }; - - this.appsStore.create(request) + this.appsStore.create(value) .subscribe({ next: () => { this.emitComplete(); diff --git a/frontend/src/app/shared/components/contents/content-list-cell.directive.ts b/frontend/src/app/shared/components/contents/content-list-cell.directive.ts index dd9dc3e95..2abc149fa 100644 --- a/frontend/src/app/shared/components/contents/content-list-cell.directive.ts +++ b/frontend/src/app/shared/components/contents/content-list-cell.directive.ts @@ -7,7 +7,7 @@ import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit, Pipe, PipeTransform, Renderer2 } from '@angular/core'; import { ResourceOwner } from '@app/framework'; -import { ContentDto, MetaFields, TableField, FieldSizes, Types, RootFieldDto, TableSettings } from '@app/shared/internal'; +import { ContentDto, FieldSizes, MetaFields, RootFieldDto, TableField, TableSettings, Types } from '@app/shared/internal'; export function getCellWidth(field: TableField, sizes: FieldSizes | undefined | null) { if (Types.is(field, RootFieldDto)) { diff --git a/frontend/src/app/shared/components/forms/geolocation-editor.component.ts b/frontend/src/app/shared/components/forms/geolocation-editor.component.ts index 4fd961dd9..c4751da8b 100644 --- a/frontend/src/app/shared/components/forms/geolocation-editor.component.ts +++ b/frontend/src/app/shared/components/forms/geolocation-editor.component.ts @@ -7,7 +7,7 @@ import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, Input, ViewChild } from '@angular/core'; import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { LocalStoreService, ResourceLoaderService, Settings, StatefulControlComponent, Types, UIOptions, ExtendedFormGroup, ValidatorsEx } from '@app/shared/internal'; +import { ExtendedFormGroup, LocalStoreService, ResourceLoaderService, Settings, StatefulControlComponent, Types, UIOptions, ValidatorsEx } from '@app/shared/internal'; declare const L: any; declare const google: any; diff --git a/frontend/src/app/shared/components/search/queries/filter-comparison.component.ts b/frontend/src/app/shared/components/search/queries/filter-comparison.component.ts index 11e8d049c..5a306e20b 100644 --- a/frontend/src/app/shared/components/search/queries/filter-comparison.component.ts +++ b/frontend/src/app/shared/components/search/queries/filter-comparison.component.ts @@ -6,7 +6,7 @@ */ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; -import { FilterComparison, LanguageDto, FilterableField, QueryModel, FilterFieldUI, getFilterUI, StatusInfo } from '@app/shared/internal'; +import { FilterableField, FilterComparison, FilterFieldUI, getFilterUI, LanguageDto, QueryModel, StatusInfo } from '@app/shared/internal'; import { ContributorsState } from '@app/shared/state/contributors.state'; @Component({ diff --git a/frontend/src/app/shared/interceptors/auth.interceptor.spec.ts b/frontend/src/app/shared/interceptors/auth.interceptor.spec.ts index 8cb24eb10..28dd2cdcb 100644 --- a/frontend/src/app/shared/interceptors/auth.interceptor.spec.ts +++ b/frontend/src/app/shared/interceptors/auth.interceptor.spec.ts @@ -5,7 +5,9 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { HttpClient, HttpHeaders, HTTP_INTERCEPTORS } from '@angular/common/http'; +/* eslint-disable deprecation/deprecation */ + +import { HTTP_INTERCEPTORS, HttpClient, HttpHeaders } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { Router } from '@angular/router'; diff --git a/frontend/src/app/shared/internal.ts b/frontend/src/app/shared/internal.ts index 106f33748..082151f55 100644 --- a/frontend/src/app/shared/internal.ts +++ b/frontend/src/app/shared/internal.ts @@ -30,6 +30,8 @@ export * from './services/schemas.service'; export * from './services/schemas.types'; export * from './services/search.service'; export * from './services/stock-photo.service'; +export * from './services/templates.service'; +export * from './services/templates.service'; export * from './services/translations.service'; export * from './services/ui.service'; export * from './services/usages.service'; @@ -70,6 +72,7 @@ export * from './state/schemas.forms'; export * from './state/schemas.state'; export * from './state/settings'; export * from './state/table-settings'; +export * from './state/templates.state'; export * from './state/ui-languages'; export * from './state/ui.state'; export * from './state/workflows.forms'; diff --git a/frontend/src/app/shared/module.ts b/frontend/src/app/shared/module.ts index 9cf190282..7f2aa4c6f 100644 --- a/frontend/src/app/shared/module.ts +++ b/frontend/src/app/shared/module.ts @@ -12,7 +12,7 @@ import { RouterModule } from '@angular/router'; import { MentionModule } from 'angular-mentions'; import { NgxDocViewerModule } from 'ngx-doc-viewer'; import { SqxFrameworkModule } from '@app/framework'; -import { AppFormComponent, AppLanguagesService, AppMustExistGuard, AppsService, AppsState, AssetComponent, AssetDialogComponent, AssetFolderComponent, AssetFolderDialogComponent, AssetFolderDropdownComponent, AssetFolderDropdownItemComponent, AssetHistoryComponent, AssetPathComponent, AssetPreviewUrlPipe, AssetScriptsState, AssetsListComponent, AssetsSelectorComponent, AssetsService, AssetsState, AssetTextEditorComponent, AssetUploaderComponent, AssetUploaderState, AssetUrlPipe, AuthInterceptor, AuthService, AutoSaveService, BackupsService, BackupsState, ClientsService, ClientsState, CommentComponent, CommentsComponent, CommentsService, ContentListCellDirective, ContentListCellResizeDirective, ContentListFieldComponent, ContentListHeaderComponent, ContentListWidthDirective, ContentMustExistGuard, ContentsColumnsPipe, ContentSelectorComponent, ContentSelectorItemComponent, ContentsService, ContentsState, ContentStatusComponent, ContentValueComponent, ContentValueEditorComponent, ContributorsService, ContributorsState, FileIconPipe, FilterComparisonComponent, FilterLogicalComponent, FilterNodeComponent, FilterOperatorPipe, GeolocationEditorComponent, GraphQlService, HelpComponent, HelpMarkdownPipe, HelpService, HistoryComponent, HistoryListComponent, HistoryMessagePipe, HistoryService, ImageCropperComponent, ImageFocusPointComponent, LanguagesService, LanguagesState, LoadAppsGuard, LoadLanguagesGuard, LoadSchemasGuard, MarkdownEditorComponent, MustBeAuthenticatedGuard, MustBeNotAuthenticatedGuard, NewsService, NotifoComponent, PlansService, PlansState, PreviewableType, QueryComponent, QueryListComponent, QueryPathComponent, ReferenceInputComponent, RichEditorComponent, RolesService, RolesState, RuleEventsState, RuleMustExistGuard, RuleSimulatorState, RulesService, RulesState, SavedQueriesComponent, SchemaCategoryComponent, SchemaMustExistGuard, SchemaMustExistPublishedGuard, SchemaMustNotBeSingletonGuard, SchemasService, SchemasState, SchemaTagSource, SearchFormComponent, SearchService, SortingComponent, StockPhotoService, TableHeaderComponent, TranslationsService, UIService, UIState, UnsetAppGuard, UsagesService, UserDtoPicture, UserIdPicturePipe, UserNamePipe, UserNameRefPipe, UserPicturePipe, UserPictureRefPipe, UsersProviderService, UsersService, WatchingUsersComponent, WorkflowsService, WorkflowsState } from './declarations'; +import { AppFormComponent, AppLanguagesService, AppMustExistGuard, AppsService, AppsState, AssetComponent, AssetDialogComponent, AssetFolderComponent, AssetFolderDialogComponent, AssetFolderDropdownComponent, AssetFolderDropdownItemComponent, AssetHistoryComponent, AssetPathComponent, AssetPreviewUrlPipe, AssetScriptsState, AssetsListComponent, AssetsSelectorComponent, AssetsService, AssetsState, AssetTextEditorComponent, AssetUploaderComponent, AssetUploaderState, AssetUrlPipe, AuthInterceptor, AuthService, AutoSaveService, BackupsService, BackupsState, ClientsService, ClientsState, CommentComponent, CommentsComponent, CommentsService, ContentListCellDirective, ContentListCellResizeDirective, ContentListFieldComponent, ContentListHeaderComponent, ContentListWidthDirective, ContentMustExistGuard, ContentsColumnsPipe, ContentSelectorComponent, ContentSelectorItemComponent, ContentsService, ContentsState, ContentStatusComponent, ContentValueComponent, ContentValueEditorComponent, ContributorsService, ContributorsState, FileIconPipe, FilterComparisonComponent, FilterLogicalComponent, FilterNodeComponent, FilterOperatorPipe, GeolocationEditorComponent, GraphQlService, HelpComponent, HelpMarkdownPipe, HelpService, HistoryComponent, HistoryListComponent, HistoryMessagePipe, HistoryService, ImageCropperComponent, ImageFocusPointComponent, LanguagesService, LanguagesState, LoadAppsGuard, LoadLanguagesGuard, LoadSchemasGuard, MarkdownEditorComponent, MustBeAuthenticatedGuard, MustBeNotAuthenticatedGuard, NewsService, NotifoComponent, PlansService, PlansState, PreviewableType, QueryComponent, QueryListComponent, QueryPathComponent, ReferenceInputComponent, RichEditorComponent, RolesService, RolesState, RuleEventsState, RuleMustExistGuard, RuleSimulatorState, RulesService, RulesState, SavedQueriesComponent, SchemaCategoryComponent, SchemaMustExistGuard, SchemaMustExistPublishedGuard, SchemaMustNotBeSingletonGuard, SchemasService, SchemasState, SchemaTagSource, SearchFormComponent, SearchService, SortingComponent, StockPhotoService, TableHeaderComponent, TemplatesService, TemplatesState, TranslationsService, UIService, UIState, UnsetAppGuard, UsagesService, UserDtoPicture, UserIdPicturePipe, UserNamePipe, UserNameRefPipe, UserPicturePipe, UserPictureRefPipe, UsersProviderService, UsersService, WatchingUsersComponent, WorkflowsService, WorkflowsState } from './declarations'; @NgModule({ imports: [ @@ -192,6 +192,8 @@ export class SqxSharedModule { SchemaTagSource, SearchService, StockPhotoService, + TemplatesService, + TemplatesState, TranslationsService, UIService, UIState, diff --git a/frontend/src/app/shared/services/app-languages.service.ts b/frontend/src/app/shared/services/app-languages.service.ts index 4d9130a47..73dbf02db 100644 --- a/frontend/src/app/shared/services/app-languages.service.ts +++ b/frontend/src/app/shared/services/app-languages.service.ts @@ -107,10 +107,8 @@ export class AppLanguagesService { } } -function parseLanguages(response: any) { - const raw: any[] = response.items; - - const items = raw.map(item => +function parseLanguages(response: { items: any[] } & Resource) { + const items = response.items.map(item => new AppLanguageDto(item._links, item.iso2Code, item.englishName, @@ -118,7 +116,7 @@ function parseLanguages(response: any) { item.isOptional, item.fallback || [])); - const _links = response._links; + const { _links } = response; return { items, _links, canCreate: hasAnyLink(_links, 'create') }; } diff --git a/frontend/src/app/shared/services/apps.service.spec.ts b/frontend/src/app/shared/services/apps.service.spec.ts index 4036e7384..4dc62307d 100644 --- a/frontend/src/app/shared/services/apps.service.spec.ts +++ b/frontend/src/app/shared/services/apps.service.spec.ts @@ -237,13 +237,12 @@ describe('AppsService', () => { }, }; - let app: AppDto; let error: ErrorDto; - appsService.postAppImage('my-app', resource, null!, version).subscribe(result => { - app = <AppDto>result; - }, e => { - error = e; + appsService.postAppImage('my-app', resource, null!, version).subscribe({ + error: e => { + error = e; + }, }); const req = httpMock.expectOne('http://service/p/api/apps/my-app/image'); @@ -253,7 +252,6 @@ describe('AppsService', () => { req.flush({}, { status: 413, statusText: 'Payload too large' }); - expect(app!).toBeUndefined(); expect(error!).toEqual(new ErrorDto(413, 'i18n:apps.uploadImageTooBig')); })); diff --git a/frontend/src/app/shared/services/apps.service.ts b/frontend/src/app/shared/services/apps.service.ts index b626a0b2a..8197a6401 100644 --- a/frontend/src/app/shared/services/apps.service.ts +++ b/frontend/src/app/shared/services/apps.service.ts @@ -122,7 +122,7 @@ export type AssetScripts = Readonly<{ [name: string]: string | null }>; export type CreateAppDto = - Readonly<{ name: string; template?: string }>; + Readonly<{ name: string }>; export type UpdateAppDto = Readonly<{ label?: string; description?: string }>; @@ -313,7 +313,7 @@ export class AppsService { } } -function parseApp(response: any) { +function parseApp(response: any & Resource) { return new AppDto(response._links, response.id, DateTime.parseISO(response.created), response.createdBy, @@ -329,7 +329,7 @@ function parseApp(response: any) { response.roleProperties); } -function parseAppSettings(response: any) { +function parseAppSettings(response: any & Resource) { return new AppSettingsDto(response._links, response.hideScheduler, response.patterns.map((x: any) => { diff --git a/frontend/src/app/shared/services/assets.service.spec.ts b/frontend/src/app/shared/services/assets.service.spec.ts index 76fae0398..76cea1d27 100644 --- a/frontend/src/app/shared/services/assets.service.spec.ts +++ b/frontend/src/app/shared/services/assets.service.spec.ts @@ -275,13 +275,12 @@ describe('AssetsService', () => { it('should return proper error if upload failed with 413', inject([AssetsService, HttpTestingController], (assetsService: AssetsService, httpMock: HttpTestingController) => { - let asset: AssetDto; let error: ErrorDto; - assetsService.postAssetFile('my-app', null!).subscribe(result => { - asset = <AssetDto>result; - }, e => { - error = e; + assetsService.postAssetFile('my-app', null!).subscribe({ + error: e => { + error = e; + }, }); const req = httpMock.expectOne('http://service/p/api/apps/my-app/assets'); @@ -291,7 +290,6 @@ describe('AssetsService', () => { req.flush({}, { status: 413, statusText: 'Payload too large' }); - expect(asset!).toBeUndefined(); expect(error!).toEqual(new ErrorDto(413, 'i18n:assets.fileTooBig')); })); @@ -327,13 +325,12 @@ describe('AssetsService', () => { }, }; - let asset: AssetDto; let error: ErrorDto; - assetsService.putAssetFile('my-app', resource, null!, version).subscribe(result => { - asset = <AssetDto>result; - }, e => { - error = e; + assetsService.putAssetFile('my-app', resource, null!, version).subscribe({ + error: e => { + error = e; + }, }); const req = httpMock.expectOne('http://service/p/api/apps/my-app/assets/123/content'); @@ -343,7 +340,6 @@ describe('AssetsService', () => { req.flush({}, { status: 413, statusText: 'Payload too large' }); - expect(asset!).toBeUndefined(); expect(error!).toEqual(new ErrorDto(413, 'i18n:assets.fileTooBig')); })); diff --git a/frontend/src/app/shared/services/assets.service.ts b/frontend/src/app/shared/services/assets.service.ts index 15cf4347a..a201c8159 100644 --- a/frontend/src/app/shared/services/assets.service.ts +++ b/frontend/src/app/shared/services/assets.service.ts @@ -172,12 +172,6 @@ export type AssetsByIds = export type AssetsByQuery = Readonly<{ query?: Query; skip?: number; tags?: Tags; take?: number; parentId?: string }>; -type AssetsResponse = - Readonly<{ total: number; items: any[]; folders: any[] } & Resource>; - -type AssetFolderResponse = - Readonly<{ total: number; items: any[]; folders: any[]; path: any[] } & Resource>; - @Injectable() export class AssetsService { constructor( @@ -216,11 +210,9 @@ export class AssetsService { }; } - return this.http.post<AssetsResponse>(url, body, options).pipe( - map(({ total, items, _links }) => { - const assets = items.map(parseAsset); - - return new AssetsDto(total, assets, _links); + return this.http.post<any>(url, body, options).pipe( + map(body => { + return parseAssets(body); }), pretifyError('i18n:assets.loadFailed')); } @@ -228,12 +220,9 @@ export class AssetsService { public getAssetFolders(appName: string, parentId: string, scope: AssetFolderScope): Observable<AssetFoldersDto> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/folders?parentId=${parentId}&scope=${scope}`); - return this.http.get<AssetFolderResponse>(url).pipe( - map(({ total, items, path, _links }) => { - const assetFolders = items.map(parseAssetFolder); - const assetPath = path.map(parseAssetFolder); - - return new AssetFoldersDto(total, assetFolders, assetPath, _links); + return this.http.get<any>(url).pipe( + map(body => { + return parseAssetFolders(body); }), pretifyError('i18n:assets.loadFoldersFailed')); } @@ -243,9 +232,7 @@ export class AssetsService { return HTTP.getVersioned(this.http, url).pipe( map(({ payload }) => { - const body = payload.body; - - return parseAsset(body); + return parseAsset(payload.body); }), pretifyError('i18n:assets.loadFailed')); } @@ -459,6 +446,12 @@ function buildQuery(q?: AssetsQuery & AssetsByQuery & AssetsByIds & AssetsByRef) return body; } +function parseAssets(response: { items: any[]; total: number } & Resource) { + const items = response.items.map(parseAsset); + + return new AssetsDto(response.total, items, response._links); +} + function parseAsset(response: any) { return new AssetDto(response._links, response._meta, response.id, @@ -480,6 +473,13 @@ function parseAsset(response: any) { response.tags || []); } +function parseAssetFolders(response: { items: any[]; path: any[]; total: number } & Resource) { + const assetFolders = response.items.map(parseAssetFolder); + const assetPath = response.path.map(parseAssetFolder); + + return new AssetFoldersDto(response.total, assetFolders, assetPath, response._links); +} + function parseAssetFolder(response: any) { return new AssetFolderDto(response._links, response.id, diff --git a/frontend/src/app/shared/services/backups.service.spec.ts b/frontend/src/app/shared/services/backups.service.spec.ts index d4a0cce07..9aa4727a8 100644 --- a/frontend/src/app/shared/services/backups.service.spec.ts +++ b/frontend/src/app/shared/services/backups.service.spec.ts @@ -109,13 +109,12 @@ describe('BackupsService', () => { it('should throw error if get restore return non 404', inject([BackupsService, HttpTestingController], (backupsService: BackupsService, httpMock: HttpTestingController) => { - let restore: RestoreDto | null; let error: any; - backupsService.getRestore().subscribe(result => { - restore = result; - }, err => { - error = err; + backupsService.getRestore().subscribe({ + error: e => { + error = e; + }, }); const req = httpMock.expectOne('http://service/p/api/apps/restore'); @@ -125,7 +124,6 @@ describe('BackupsService', () => { req.flush({}, { status: 500, statusText: '500' }); - expect(restore!).toBeUndefined(); expect(error)!.toBeDefined(); })); diff --git a/frontend/src/app/shared/services/backups.service.ts b/frontend/src/app/shared/services/backups.service.ts index 2973e5da1..2aa7f7f77 100644 --- a/frontend/src/app/shared/services/backups.service.ts +++ b/frontend/src/app/shared/services/backups.service.ts @@ -74,10 +74,8 @@ export class BackupsService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/backups`); return this.http.get<{ items: any[]; _links: {} } & Resource>(url).pipe( - map(({ items, _links }) => { - const backups = items.map(parseBackup); - - return new BackupsDto(backups.length, backups, _links); + map(body => { + return parseBackups(body); }), pretifyError('i18n:backups.loadFailed')); } @@ -134,6 +132,12 @@ export class BackupsService { } } +function parseBackups(response: { items: any[] } & Resource) { + const items = response.items.map(parseBackup); + + return new BackupsDto(items.length, items, response._links); +} + function parseRestore(response: any) { return new RestoreDto( response.url, @@ -143,7 +147,7 @@ function parseRestore(response: any) { response.log); } -function parseBackup(response: any) { +function parseBackup(response: any & Resource) { return new BackupDto(response._links, response.id, DateTime.parseISO(response.started), diff --git a/frontend/src/app/shared/services/clients.service.ts b/frontend/src/app/shared/services/clients.service.ts index a9a6ec625..953c71673 100644 --- a/frontend/src/app/shared/services/clients.service.ts +++ b/frontend/src/app/shared/services/clients.service.ts @@ -135,10 +135,8 @@ export class ClientsService { } } -function parseClients(response: any): ClientsPayload { - const raw: any[] = response.items; - - const items = raw.map(item => +function parseClients(response: { items: any[] } & Resource): ClientsPayload { + const items = response.items.map(item => new ClientDto(item._links, item.id, item.name || item.id, @@ -148,7 +146,7 @@ function parseClients(response: any): ClientsPayload { item.apiTrafficLimit, item.allowAnonymous)); - const _links = response._links; + const { _links } = response; return { items, _links, canCreate: hasAnyLink(_links, 'create') }; } diff --git a/frontend/src/app/shared/services/comments.service.ts b/frontend/src/app/shared/services/comments.service.ts index 12747e498..ee33244a0 100644 --- a/frontend/src/app/shared/services/comments.service.ts +++ b/frontend/src/app/shared/services/comments.service.ts @@ -68,28 +68,7 @@ export class CommentsService { return this.http.get<any>(url, options).pipe( map(body => { - const comments = new CommentsDto( - body.createdComments.map((item: any) => { - return new CommentDto( - item.id, - DateTime.parseISO(item.time), - item.text, - item.url, - item.user); - }), - body.updatedComments.map((item: any) => { - return new CommentDto( - item.id, - DateTime.parseISO(item.time), - item.text, - item.url, - item.user); - }), - body.deletedComments, - new Version(body.version), - ); - - return comments; + return parseComments(body); }), pretifyError('i18n:comments.loadFailed')); } @@ -99,14 +78,7 @@ export class CommentsService { return this.http.post<any>(url, dto).pipe( map(body => { - const comment = new CommentDto( - body.id, - DateTime.parseISO(body.time), - body.text, - body.url, - body.user); - - return comment; + return parseComment(body); }), pretifyError('i18n:comments.createFailed')); } @@ -125,3 +97,20 @@ export class CommentsService { pretifyError('i18n:comments.deleteFailed')); } } +function parseComments(response: any) { + return new CommentsDto( + response.createdComments.map(parseComment), + response.updatedComments.map(parseComment), + response.deletedComments, + new Version(response.version)); +} + +function parseComment(response: any) { + return new CommentDto( + response.id, + DateTime.parseISO(response.time), + response.text, + response.url, + response.user); +} + diff --git a/frontend/src/app/shared/services/contents.service.ts b/frontend/src/app/shared/services/contents.service.ts index d61b00fc3..e1e4013ca 100644 --- a/frontend/src/app/shared/services/contents.service.ts +++ b/frontend/src/app/shared/services/contents.service.ts @@ -136,9 +136,6 @@ export type ContentsBySchedule = type ContentsByQuery = Readonly<{ query?: Query; skip?: number; take?: number }> & ContentsQuery; -type ContentsResponse = - Readonly<{ total: number; items: []; statuses: StatusInfo[] } & Resource>; - @Injectable() export class ContentsService { constructor( @@ -163,11 +160,9 @@ export class ContentsService { }; } - return this.http.post<ContentsResponse>(url, body, options).pipe( - map(({ total, items, statuses, _links }) => { - const contents = items.map(parseContent); - - return new ContentsDto(statuses, total, contents, _links); + return this.http.post<any>(url, body, options).pipe( + map(body => { + return parseContents(body); }), pretifyError('i18n:contents.loadFailed')); } @@ -204,11 +199,9 @@ export class ContentsService { }; } - return this.http.post<ContentsResponse>(url, body, options).pipe( - map(({ total, items, statuses, _links }) => { - const contents = items.map(parseContent); - - return new ContentsDto(statuses, total, contents, _links); + return this.http.post<any>(url, body, options).pipe( + map(body => { + return parseContents(body); }), pretifyError('i18n:contents.loadFailed')); } @@ -228,11 +221,9 @@ export class ContentsService { }; } - return this.http.get<ContentsResponse>(url, options).pipe( - map(({ total, items, statuses, _links }) => { - const contents = items.map(parseContent); - - return new ContentsDto(statuses, total, contents, _links); + return this.http.get<any>(url, options).pipe( + map(body => { + return parseContents(body); }), pretifyError('i18n:contents.loadFailed')); } @@ -242,11 +233,9 @@ export class ContentsService { const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/referencing?${fullQuery}`); - return this.http.get<ContentsResponse>(url).pipe( - map(({ total, items, statuses, _links }) => { - const contents = items.map(parseContent); - - return new ContentsDto(statuses, total, contents, _links); + return this.http.get<any>(url).pipe( + map(body => { + return parseContents(body); }), pretifyError('i18n:contents.loadFailed')); } @@ -399,7 +388,13 @@ function buildQuery(q?: ContentsByQuery) { return body; } -function parseContent(response: any) { +function parseContents(response: { items: any[]; total: number; statuses: any } & Resource) { + const items = response.items.map(parseContent); + + return new ContentsDto(response.statuses, response.total, items, response._links); +} + +function parseContent(response: any & Resource) { return new ContentDto(response._links, response.id, DateTime.parseISO(response.created), response.createdBy, diff --git a/frontend/src/app/shared/services/contributors.service.ts b/frontend/src/app/shared/services/contributors.service.ts index a84aaba53..9e2c002e2 100644 --- a/frontend/src/app/shared/services/contributors.service.ts +++ b/frontend/src/app/shared/services/contributors.service.ts @@ -82,9 +82,7 @@ export class ContributorsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version).pipe( - mapVersioned(payload => { - const body = payload.body; - + mapVersioned(({ body }) => { return parseContributors(body); }), tap(() => { @@ -94,10 +92,8 @@ export class ContributorsService { } } -function parseContributors(response: any) { - const raw: any[] = response.items; - - const items = raw.map(item => +function parseContributors(response: { items: any[]; maxContributors: number } & Resource) { + const items = response.items.map(item => new ContributorDto(item._links, item.contributorId, item.contributorName, diff --git a/frontend/src/app/shared/services/help.service.spec.ts b/frontend/src/app/shared/services/help.service.spec.ts index 9f07cb038..a9183f8d2 100644 --- a/frontend/src/app/shared/services/help.service.spec.ts +++ b/frontend/src/app/shared/services/help.service.spec.ts @@ -5,6 +5,8 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ +/* eslint-disable deprecation/deprecation */ + import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { HelpService } from '@app/shared/internal'; diff --git a/frontend/src/app/shared/services/history.service.ts b/frontend/src/app/shared/services/history.service.ts index 0dd9c168c..ffdb674bf 100644 --- a/frontend/src/app/shared/services/history.service.ts +++ b/frontend/src/app/shared/services/history.service.ts @@ -82,17 +82,19 @@ export class HistoryService { return this.http.get<any[]>(url, options).pipe( map(body => { - const history = body.map(item => - new HistoryEventDto( - item.eventId, - item.actor, - item.eventType, - item.message, - DateTime.parseISO(item.created), - new Version(item.version.toString()))); - - return history; + return parseHistory(body); }), pretifyError('i18n:history.loadFailed')); } } + +function parseHistory(response: any[]) { + return response.map(item => new HistoryEventDto( + item.eventId, + item.actor, + item.eventType, + item.message, + DateTime.parseISO(item.created), + new Version(item.version.toString()))); +} + diff --git a/frontend/src/app/shared/services/languages.service.ts b/frontend/src/app/shared/services/languages.service.ts index 41872280e..3f882e399 100644 --- a/frontend/src/app/shared/services/languages.service.ts +++ b/frontend/src/app/shared/services/languages.service.ts @@ -32,13 +32,14 @@ export class LanguagesService { return this.http.get<any[]>(url).pipe( map(body => { - const languages = body.map(item => - new LanguageDto( - item.iso2Code, - item.englishName)); - - return languages; + return parseLanguages(body); }), pretifyError('i18n:languages.loadFailed')); } } + +function parseLanguages(response: any[]) { + return response.map(item => new LanguageDto( + item.iso2Code, + item.englishName)); +} diff --git a/frontend/src/app/shared/services/news.service.ts b/frontend/src/app/shared/services/news.service.ts index 316611449..23a402131 100644 --- a/frontend/src/app/shared/services/news.service.ts +++ b/frontend/src/app/shared/services/news.service.ts @@ -40,18 +40,18 @@ export class NewsService { return this.http.get<any>(url).pipe( map(body => { - const items: any[] = body.features; - - const features = new FeaturesDto( - items.map(item => - new FeatureDto( - item.name, - item.text), - ), - body.version); - - return features; + return parseFeatures(body); }), pretifyError('i18n:features.loadFailed')); } } + +function parseFeatures(body: { features: any[]; version: number }) { + return new FeaturesDto( + body.features.map(item => + new FeatureDto( + item.name, + item.text), + ), + body.version); +} diff --git a/frontend/src/app/shared/services/plans.service.ts b/frontend/src/app/shared/services/plans.service.ts index 4664a9234..55cb113b4 100644 --- a/frontend/src/app/shared/services/plans.service.ts +++ b/frontend/src/app/shared/services/plans.service.ts @@ -51,30 +51,7 @@ export class PlansService { return HTTP.getVersioned(this.http, url).pipe( mapVersioned(({ body }) => { - const items: any[] = body.plans; - - const { hasPortal, currentPlanId, planOwner } = body; - - const plans = { - currentPlanId, - planOwner, - plans: items.map(item => - new PlanDto( - item.id, - item.name, - item.costs, - item.confirmText, - item.yearlyId, - item.yearlyCosts, - item.yearlyConfirmText, - item.maxApiBytes, - item.maxApiCalls, - item.maxAssetSize, - item.maxContributors)), - hasPortal, - }; - - return plans; + return parsePlans(body); }), pretifyError('i18n:plans.loadFailed')); } @@ -83,8 +60,8 @@ export class PlansService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/plan`); return HTTP.putVersioned(this.http, url, dto, version).pipe( - mapVersioned(payload => { - return <PlanChangedDto>payload.body; + mapVersioned(({ body }) => { + return <PlanChangedDto>body; }), tap(() => { this.analytics.trackEvent('Plan', 'Changed', appName); @@ -92,3 +69,26 @@ export class PlansService { pretifyError('i18n:plans.changeFailed')); } } + +function parsePlans(body: { plans: any[]; hasPortal: boolean; currentPlanId: string; planOwner: string }) { + const { hasPortal, currentPlanId, planOwner } = body; + + return { + currentPlanId, + planOwner, + plans: body.plans.map(item => new PlanDto( + item.id, + item.name, + item.costs, + item.confirmText, + item.yearlyId, + item.yearlyCosts, + item.yearlyConfirmText, + item.maxApiBytes, + item.maxApiCalls, + item.maxAssetSize, + item.maxContributors)), + hasPortal, + }; +} + diff --git a/frontend/src/app/shared/services/roles.service.ts b/frontend/src/app/shared/services/roles.service.ts index 2b186ce36..0e737e668 100644 --- a/frontend/src/app/shared/services/roles.service.ts +++ b/frontend/src/app/shared/services/roles.service.ts @@ -129,7 +129,7 @@ export function parseRoles(response: any) { item.properties, item.isDefaultRole)); - const _links = response._links; + const { _links } = response; return { items, _links, canCreate: hasAnyLink(_links, 'create') }; } diff --git a/frontend/src/app/shared/services/rules.service.ts b/frontend/src/app/shared/services/rules.service.ts index d6cf6b574..077ffa0f7 100644 --- a/frontend/src/app/shared/services/rules.service.ts +++ b/frontend/src/app/shared/services/rules.service.ts @@ -236,9 +236,7 @@ export class RulesService { return this.http.get<any>(url).pipe( map(body => { - const actions = parseActions(body); - - return actions; + return parseActions(body); }), pretifyError('i18n:rules.loadFailed')); } @@ -246,11 +244,9 @@ export class RulesService { public getRules(appName: string): Observable<RulesDto> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/rules`); - return this.http.get<{ items: [] } & Resource & { runningRuleId?: string }>(url).pipe( - map(({ items, _links, runningRuleId }) => { - const rules = items.map(parseRule); - - return new RulesDto(rules, _links, runningRuleId); + return this.http.get<any>(url).pipe( + map(body => { + return parseRules(body); }), pretifyError('i18n:rules.loadFailed')); } @@ -344,11 +340,9 @@ export class RulesService { public getEvents(appName: string, take: number, skip: number, ruleId?: string): Observable<RuleEventsDto> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/rules/events?take=${take}&skip=${skip}&ruleId=${ruleId || ''}`); - return this.http.get<{ items: any[]; total: number } & Resource>(url).pipe( - map(({ items, total, _links }) => { - const ruleEvents = items.map(parseRuleEvent); - - return new RuleEventsDto(total, ruleEvents, _links); + return this.http.get<any>(url).pipe( + map(body => { + return parseEvents(body); }), pretifyError('i18n:rules.ruleEvents.loadFailed')); } @@ -356,11 +350,9 @@ export class RulesService { public getSimulatedEvents(appName: string, ruleId: string): Observable<SimulatedRuleEventsDto> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/rules/${ruleId}/simulate`); - return this.http.get<{ items: any[]; total: number } & Resource>(url).pipe( - map(({ items, total, _links }) => { - const simulatedRuleEvents = items.map(parseSimulatedRuleEvent); - - return new SimulatedRuleEventsDto(total, simulatedRuleEvents, _links); + return this.http.get<any>(url).pipe( + map(body => { + return parseSimulatedEvents(body); }), pretifyError('i18n:rules.ruleEvents.loadFailed')); } @@ -390,6 +382,24 @@ export class RulesService { } } +function parseSimulatedEvents(response: { items: any[]; total: number } & Resource) { + const simulatedRuleEvents = response.items.map(parseSimulatedRuleEvent); + + return new SimulatedRuleEventsDto(response.total, simulatedRuleEvents, response._links); +} + +function parseEvents(response: { items: any[]; total: number } & Resource) { + const ruleEvents = response.items.map(parseRuleEvent); + + return new RuleEventsDto(response.total, ruleEvents, response._links); +} + +function parseRules(response: { items: any[]; runningRuleId?: string } & Resource) { + const rules = response.items.map(parseRule); + + return new RulesDto(rules, response._links, response.runningRuleId); +} + function parseActions(response: any) { const actions: { [name: string]: RuleElementDto } = {}; diff --git a/frontend/src/app/shared/services/schemas.service.ts b/frontend/src/app/shared/services/schemas.service.ts index 133c01b7d..b50d4b759 100644 --- a/frontend/src/app/shared/services/schemas.service.ts +++ b/frontend/src/app/shared/services/schemas.service.ts @@ -673,10 +673,8 @@ export class SchemasService { } } -function parseSchemas(response: any) { - const raw: any[] = response.items; - - const items = raw.map(parseSchema); +function parseSchemas(response: { items: any[] } & Resource) { + const items = response.items.map(parseSchema); const _links = response._links; diff --git a/frontend/src/app/shared/services/search.service.ts b/frontend/src/app/shared/services/search.service.ts index 5fde15e6c..9b427be28 100644 --- a/frontend/src/app/shared/services/search.service.ts +++ b/frontend/src/app/shared/services/search.service.ts @@ -38,17 +38,21 @@ export class SearchService { public getResults(appName: string, query: string): Observable<ReadonlyArray<SearchResultDto>> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/search/?query=${encodeURIComponent(query)}`); - return this.http.get<ReadonlyArray<any>>(url).pipe( + return this.http.get<any[]>(url).pipe( map(body => { - const results = body.map(item => - new SearchResultDto( - item._links, - item.name, - item.type, - item.label)); - - return results; + return parseResults(body); }), pretifyError('i18n:search.searchFailed')); } } + +function parseResults(body: any[]) { + const results = body.map(item => new SearchResultDto( + item._links, + item.name, + item.type, + item.label)); + + return results; +} + diff --git a/frontend/src/app/shared/services/stock-photo.service.spec.ts b/frontend/src/app/shared/services/stock-photo.service.spec.ts index 889220cb7..6e791368c 100644 --- a/frontend/src/app/shared/services/stock-photo.service.spec.ts +++ b/frontend/src/app/shared/services/stock-photo.service.spec.ts @@ -5,6 +5,8 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ +/* eslint-disable deprecation/deprecation */ + import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { StockPhotoDto, StockPhotoService } from '@app/shared/internal'; diff --git a/frontend/src/app/shared/services/stock-photo.service.ts b/frontend/src/app/shared/services/stock-photo.service.ts index 02ebcc109..823734692 100644 --- a/frontend/src/app/shared/services/stock-photo.service.ts +++ b/frontend/src/app/shared/services/stock-photo.service.ts @@ -32,14 +32,17 @@ export class StockPhotoService { return this.http.get<any[]>(url).pipe( map(body => { - return body.map(x => - new StockPhotoDto( - x.url, - x.thumbUrl, - x.user, - x.userProfileUrl, - )); + return parseImages(body); }), catchError(() => of([]))); } } +function parseImages(body: any[]) { + return body.map(x => new StockPhotoDto( + x.url, + x.thumbUrl, + x.user, + x.userProfileUrl, + )); +} + diff --git a/frontend/src/app/shared/services/templates.service.spec.ts b/frontend/src/app/shared/services/templates.service.spec.ts new file mode 100644 index 000000000..94ada8f54 --- /dev/null +++ b/frontend/src/app/shared/services/templates.service.spec.ts @@ -0,0 +1,128 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { inject, TestBed } from '@angular/core/testing'; +import { ApiUrlConfig, Resource, ResourceLinks, TemplateDetailsDto, TemplateDto, TemplatesDto, TemplatesService } from '@app/shared/internal'; + +describe('TemplatesService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + ], + providers: [ + TemplatesService, + { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') }, + ], + }); + }); + + afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => { + httpMock.verify(); + })); + + it('should make get request to get templates', + inject([TemplatesService, HttpTestingController], (templatesService: TemplatesService, httpMock: HttpTestingController) => { + let templates: TemplatesDto; + + templatesService.getTemplates().subscribe(result => { + templates = result; + }); + + const req = httpMock.expectOne('http://service/p/api/templates'); + + expect(req.request.method).toEqual('GET'); + expect(req.request.headers.get('If-Match')).toBeNull(); + + req.flush({ + items: [ + templateResponse(1), + templateResponse(2), + ], + }); + + expect(templates!).toEqual( + new TemplatesDto(2, [ + createTemplate(1), + createTemplate(2), + ], {})); + })); + + it('should make get request to get template', + inject([TemplatesService, HttpTestingController], (templatesService: TemplatesService, httpMock: HttpTestingController) => { + let template: TemplateDetailsDto; + + const resource: Resource = { + _links: { + self: { method: 'GET', href: '/api/templates/my-template' }, + }, + }; + + templatesService.getTemplate(resource).subscribe(result => { + template = result; + }); + + const req = httpMock.expectOne('http://service/p/api/templates/my-template'); + + expect(req.request.method).toEqual('GET'); + expect(req.request.headers.get('If-Match')).toBeNull(); + + req.flush(templateDetailsResponse(1)); + + expect(template!).toEqual(createTemplateDetails(1)); + })); + + function templateResponse(id: number, suffix = '') { + const key = `${id}${suffix}`; + + return { + name: `name${key}`, + title: `Title ${key}`, + description: `Description ${key}`, + _links: { + self: { + method: 'GET', href: `/templates/name${key}`, + }, + }, + }; + } + + function templateDetailsResponse(id: number, suffix = '') { + const key = `${id}${suffix}`; + + return { + details: `Details ${key}`, + _links: { + self: { + method: 'GET', href: `/templates/name${id}`, + }, + }, + }; + } +}); + +export function createTemplate(id: number, suffix = '') { + const links: ResourceLinks = { + self: { method: 'GET', href: `/templates/name${id}` }, + }; + + const key = `${id}${suffix}`; + + return new TemplateDto(links, `name${key}`, `Title ${key}`, `Description ${key}`); +} + + +export function createTemplateDetails(id: number, suffix = '') { + const links: ResourceLinks = { + self: { method: 'GET', href: `/templates/name${id}` }, + }; + + const key = `${id}${suffix}`; + + return new TemplateDetailsDto(links, `Details ${key}`); +} \ No newline at end of file diff --git a/frontend/src/app/shared/services/templates.service.ts b/frontend/src/app/shared/services/templates.service.ts new file mode 100644 index 000000000..f964a42c0 --- /dev/null +++ b/frontend/src/app/shared/services/templates.service.ts @@ -0,0 +1,83 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { ApiUrlConfig, pretifyError, Resource, ResourceLinks, ResultSet } from '@app/framework'; + +export class TemplatesDto extends ResultSet<TemplateDto> { +} + +export class TemplateDto { + public readonly _links: ResourceLinks; + + constructor(links: ResourceLinks, + public readonly name: string, + public readonly title: string, + public readonly description: string, + ) { + this._links = links; + } +} + +export class TemplateDetailsDto { + public readonly _links: ResourceLinks; + + constructor(links: ResourceLinks, + public readonly details: string, + ) { + this._links = links; + } +} + +@Injectable() +export class TemplatesService { + constructor( + private readonly http: HttpClient, + private readonly apiUrl: ApiUrlConfig, + ) { + } + + public getTemplates(): Observable<TemplatesDto> { + const url = this.apiUrl.buildUrl('api/templates'); + + return this.http.get<any>(url).pipe( + map(body => { + return parseTemplates(body); + }), + pretifyError('i18n:templates.loadFailed')); + } + + public getTemplate(resource: Resource): Observable<TemplateDetailsDto> { + const link = resource._links['self']; + + const url = this.apiUrl.buildUrl(link.href); + + return this.http.get<any>(url).pipe( + map(body => { + return parseTemplateDetails(body); + }), + pretifyError('i18n:templates.loadFailed')); + } +} + +function parseTemplates(response: { items: any[] } & Resource) { + const items = response.items.map(item => + new TemplateDto(item._links, + item.name, + item.title, + item.description)); + + return new TemplatesDto(items.length, items, response._links); +} + +function parseTemplateDetails(response: any & Resource) { + return new TemplateDetailsDto(response._links, + response.details); +} \ No newline at end of file diff --git a/frontend/src/app/shared/services/translations.service.ts b/frontend/src/app/shared/services/translations.service.ts index c1fadef2b..d456aabdb 100644 --- a/frontend/src/app/shared/services/translations.service.ts +++ b/frontend/src/app/shared/services/translations.service.ts @@ -35,8 +35,13 @@ export class TranslationsService { return this.http.post<any>(url, request).pipe( map(body => { - return new TranslationDto(body.result, body.text); + return parseTranslation(body); }), pretifyError('i18n:translate.translateFailed')); } } + +function parseTranslation(body: any): TranslationDto { + return new TranslationDto(body.result, body.text); +} + diff --git a/frontend/src/app/shared/services/ui.service.spec.ts b/frontend/src/app/shared/services/ui.service.spec.ts index 42940d296..e61dcfa32 100644 --- a/frontend/src/app/shared/services/ui.service.spec.ts +++ b/frontend/src/app/shared/services/ui.service.spec.ts @@ -5,6 +5,8 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ +/* eslint-disable deprecation/deprecation */ + import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { inject, TestBed } from '@angular/core/testing'; import { ApiUrlConfig, UIService, UISettingsDto } from '@app/shared/internal'; diff --git a/frontend/src/app/shared/services/usages.service.ts b/frontend/src/app/shared/services/usages.service.ts index 590c241e0..8b733df9f 100644 --- a/frontend/src/app/shared/services/usages.service.ts +++ b/frontend/src/app/shared/services/usages.service.ts @@ -76,7 +76,7 @@ export class UsagesService { return this.http.get<any>(url).pipe( map(body => { - return new CurrentStorageDto(body.size, body.maxAllowed); + return parseCurrentStorage(body); }), pretifyError('i18n:usages.loadTodayStorageFailed')); } @@ -86,30 +86,7 @@ export class UsagesService { return this.http.get<any>(url).pipe( map(body => { - const details: { [category: string]: CallsUsagePerDateDto[] } = {}; - - for (const [category, value] of Object.entries(body.details)) { - details[category] = (value as any).map((item: any) => - new CallsUsagePerDateDto( - DateTime.parseISO(item.date), - item.totalBytes, - item.totalCalls, - item.averageElapsedMs)); - } - - const usages = - new CallsUsageDto( - body.allowedBytes, - body.allowedCalls, - body.blockingCalls, - body.totalBytes, - body.totalCalls, - body.monthBytes, - body.monthCalls, - body.averageElapsedMs, - details); - - return usages; + return parseCallsUsage(body); }), pretifyError('i18n:usages.loadCallsFailed')); } @@ -119,14 +96,46 @@ export class UsagesService { return this.http.get<any[]>(url).pipe( map(body => { - const usages = body.map(item => - new StorageUsagePerDateDto( - DateTime.parseISO(item.date), - item.totalCount, - item.totalSize)); - - return usages; + return parseStorageUser(body); }), pretifyError('i18n:usages.loadStorageFailed')); } } + +function parseCurrentStorage(response: any): CurrentStorageDto { + return new CurrentStorageDto(response.size, response.maxAllowed); +} + +function parseCallsUsage(response: any) { + const details: { [category: string]: CallsUsagePerDateDto[] } = {}; + + for (const [category, value] of Object.entries(response.details)) { + details[category] = (value as any).map((item: any) => new CallsUsagePerDateDto( + DateTime.parseISO(item.date), + item.totalBytes, + item.totalCalls, + item.averageElapsedMs)); + } + + const usages = new CallsUsageDto( + response.allowedBytes, + response.allowedCalls, + response.blockingCalls, + response.totalBytes, + response.totalCalls, + response.monthBytes, + response.monthCalls, + response.averageElapsedMs, + details); + + return usages; +} + +function parseStorageUser(response: any[]) { + const usages = response.map(item => new StorageUsagePerDateDto( + DateTime.parseISO(item.date), + item.totalCount, + item.totalSize)); + + return usages; +} diff --git a/frontend/src/app/shared/services/users-provider.service.ts b/frontend/src/app/shared/services/users-provider.service.ts index 8df9e40fc..69948aec1 100644 --- a/frontend/src/app/shared/services/users-provider.service.ts +++ b/frontend/src/app/shared/services/users-provider.service.ts @@ -6,8 +6,7 @@ */ import { Injectable } from '@angular/core'; -import { ConnectableObservable, Observable, of } from 'rxjs'; -import { catchError, map, publishLast, share } from 'rxjs/operators'; +import { catchError, map, Observable, of, share, shareReplay } from 'rxjs'; import { AuthService } from './auth.service'; import { UserDto, UsersService } from './users.service'; @@ -25,17 +24,14 @@ export class UsersProviderService { let result = this.caches[id]; if (!result) { - const request = + result = this.usersService.getUser(id).pipe( catchError(() => { return of(new UserDto('Unknown', 'Unknown')); }), - publishLast()); + shareReplay(1)); - (<ConnectableObservable<any>>request).connect(); - - // eslint-disable-next-line no-multi-assign - result = this.caches[id] = request; + this.caches[id] = result; } return result.pipe( diff --git a/frontend/src/app/shared/services/users.service.ts b/frontend/src/app/shared/services/users.service.ts index de15e9efa..e08c64ea2 100644 --- a/frontend/src/app/shared/services/users.service.ts +++ b/frontend/src/app/shared/services/users.service.ts @@ -40,12 +40,7 @@ export class UsersService { return this.http.get<any[]>(url).pipe( map(body => { - const users = body.map(item => - new UserDto( - item.id, - item.displayName)); - - return users; + return parseUsers(body); }), pretifyError('i18n:users.loadFailed')); } @@ -55,11 +50,7 @@ export class UsersService { return this.http.get<any>(url).pipe( map(body => { - const user = new UserDto( - body.id, - body.displayName); - - return user; + return parseUser(body); }), pretifyError('i18n:users.loadUserFailed')); } @@ -74,3 +65,14 @@ export class UsersService { pretifyError('i18n:users.loadUserFailed')); } } + +function parseUsers(response: any[]) { + return response.map(parseUser); +} + +function parseUser(response: any) { + return new UserDto( + response.id, + response.displayName); +} + diff --git a/frontend/src/app/shared/services/workflows.service.ts b/frontend/src/app/shared/services/workflows.service.ts index 509dda573..33a5b5b4f 100644 --- a/frontend/src/app/shared/services/workflows.service.ts +++ b/frontend/src/app/shared/services/workflows.service.ts @@ -273,10 +273,8 @@ export class WorkflowsService { } } -function parseWorkflows(response: any) { - const raw: any[] = response.items; - - const items = raw.map(parseWorkflow); +function parseWorkflows(response: { items: any[]; errors: string[] } & Resource) { + const items = response.items.map(parseWorkflow); const { errors, _links } = response; diff --git a/frontend/src/app/shared/state/apps.forms.ts b/frontend/src/app/shared/state/apps.forms.ts index 3e29a17b7..a6fc6a67a 100644 --- a/frontend/src/app/shared/state/apps.forms.ts +++ b/frontend/src/app/shared/state/apps.forms.ts @@ -8,7 +8,7 @@ /* eslint-disable no-useless-escape */ import { FormControl, Validators } from '@angular/forms'; -import { Form, TemplatedFormArray, ExtendedFormGroup, ValidatorsEx } from '@app/framework'; +import { ExtendedFormGroup, Form, TemplatedFormArray, ValidatorsEx } from '@app/framework'; import { AppDto, AppSettingsDto, CreateAppDto, UpdateAppDto, UpdateAppSettingsDto } from './../services/apps.service'; export class CreateAppForm extends Form<ExtendedFormGroup, CreateAppDto> { diff --git a/frontend/src/app/shared/state/asset-uploader.state.ts b/frontend/src/app/shared/state/asset-uploader.state.ts index 0132f2a03..787a3f321 100644 --- a/frontend/src/app/shared/state/asset-uploader.state.ts +++ b/frontend/src/app/shared/state/asset-uploader.state.ts @@ -6,8 +6,7 @@ */ import { Injectable } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; -import { map, publishReplay, refCount, takeUntil } from 'rxjs/operators'; +import { map, Observable, shareReplay, Subject, takeUntil } from 'rxjs'; import { DialogService, MathHelper, State, Types } from '@app/framework'; import { AssetDto, AssetsService } from './../services/assets.service'; import { AppsState } from './apps.state'; @@ -97,17 +96,20 @@ export class AssetUploaderState extends State<Snapshot> { } else { return event; } - }), - publishReplay(), refCount()); + }), shareReplay()); - stream.subscribe(event => { - if (Types.isNumber(event)) { - upload = this.update(upload, { progress: event }); - } - }, () => { - upload = this.remove(upload, { status: 'Failed' }); - }, () => { - upload = this.remove(upload, { status: 'Completed', progress: 100 }); + stream.subscribe({ + next: event => { + if (Types.isNumber(event)) { + upload = this.update(upload, { progress: event }); + } + }, + error: () => { + upload = this.remove(upload, { status: 'Failed' }); + }, + complete: () => { + upload = this.remove(upload, { status: 'Completed', progress: 100 }); + }, }); return stream; diff --git a/frontend/src/app/shared/state/assets.forms.ts b/frontend/src/app/shared/state/assets.forms.ts index d4edb0bb8..662818b54 100644 --- a/frontend/src/app/shared/state/assets.forms.ts +++ b/frontend/src/app/shared/state/assets.forms.ts @@ -7,7 +7,7 @@ import { FormControl, Validators } from '@angular/forms'; import slugify from 'slugify'; -import { Form, Mutable, TemplatedFormArray, Types, ExtendedFormGroup } from '@app/framework'; +import { ExtendedFormGroup, Form, Mutable, TemplatedFormArray, Types } from '@app/framework'; import { AnnotateAssetDto, AssetDto, AssetFolderDto, RenameAssetFolderDto, RenameAssetTagDto } from './../services/assets.service'; export class AnnotateAssetForm extends Form<ExtendedFormGroup, AnnotateAssetDto, AssetDto> { diff --git a/frontend/src/app/shared/state/assets.state.spec.ts b/frontend/src/app/shared/state/assets.state.spec.ts index 30199ad66..53645372f 100644 --- a/frontend/src/app/shared/state/assets.state.spec.ts +++ b/frontend/src/app/shared/state/assets.state.spec.ts @@ -176,7 +176,7 @@ describe('AssetsState', () => { assetsState.search(query).subscribe(); expect(assetsState.snapshot.query).toEqual(query); - expect(assetsState.snapshot.ref).toBeNull(null); + expect(assetsState.snapshot.ref).toBeNull(); }); }); diff --git a/frontend/src/app/shared/state/backups.forms.ts b/frontend/src/app/shared/state/backups.forms.ts index 6f2ba9d88..c3ccc0866 100644 --- a/frontend/src/app/shared/state/backups.forms.ts +++ b/frontend/src/app/shared/state/backups.forms.ts @@ -8,7 +8,7 @@ /* eslint-disable no-useless-escape */ import { FormControl, Validators } from '@angular/forms'; -import { Form, hasNoValue$, ExtendedFormGroup, ValidatorsEx } from '@app/framework'; +import { ExtendedFormGroup, Form, hasNoValue$, ValidatorsEx } from '@app/framework'; import { StartRestoreDto } from './../services/backups.service'; export class RestoreForm extends Form<ExtendedFormGroup, StartRestoreDto> { diff --git a/frontend/src/app/shared/state/clients.forms.ts b/frontend/src/app/shared/state/clients.forms.ts index 3f9b70c6c..d2d5f2644 100644 --- a/frontend/src/app/shared/state/clients.forms.ts +++ b/frontend/src/app/shared/state/clients.forms.ts @@ -8,7 +8,7 @@ /* eslint-disable no-useless-escape */ import { FormControl, Validators } from '@angular/forms'; -import { Form, hasNoValue$, ExtendedFormGroup, ValidatorsEx } from '@app/framework'; +import { ExtendedFormGroup, Form, hasNoValue$, ValidatorsEx } from '@app/framework'; import { ClientDto, CreateClientDto, UpdateClientDto } from './../services/clients.service'; export class RenameClientForm extends Form<ExtendedFormGroup, UpdateClientDto, ClientDto> { diff --git a/frontend/src/app/shared/state/comments.form.ts b/frontend/src/app/shared/state/comments.form.ts index 797588ecd..1ba9c21d6 100644 --- a/frontend/src/app/shared/state/comments.form.ts +++ b/frontend/src/app/shared/state/comments.form.ts @@ -6,7 +6,7 @@ */ import { FormControl, Validators } from '@angular/forms'; -import { Form, ExtendedFormGroup } from '@app/framework'; +import { ExtendedFormGroup, Form } from '@app/framework'; import { UpsertCommentDto } from './../services/comments.service'; export class UpsertCommentForm extends Form<ExtendedFormGroup, UpsertCommentDto> { diff --git a/frontend/src/app/shared/state/contents.forms.spec.ts b/frontend/src/app/shared/state/contents.forms.spec.ts index 795850cb9..10cde96d1 100644 --- a/frontend/src/app/shared/state/contents.forms.spec.ts +++ b/frontend/src/app/shared/state/contents.forms.spec.ts @@ -798,11 +798,11 @@ describe('ContentForm', () => { const a = form[key]; const e = test[key]; - expect(a).toBe(e, `Expected ${key} of ${path} to be <${e}>, but found <${a}>.`); + expect(a).withContext(`Expected ${key} of ${path} to be <${e}>, but found <${a}>.`).toEqual(e); } } } else { - expect(form).not.toBeNull(`Expected to find form ${path}, but form not found.`); + expect(form).withContext(`Expected to find form ${path}, but form not found.`).not.toBeNull(); } } }); diff --git a/frontend/src/app/shared/state/contents.forms.ts b/frontend/src/app/shared/state/contents.forms.ts index af1099455..53dc3025e 100644 --- a/frontend/src/app/shared/state/contents.forms.ts +++ b/frontend/src/app/shared/state/contents.forms.ts @@ -6,8 +6,9 @@ */ import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { BehaviorSubject, distinctUntilChanged, Observable } from 'rxjs'; -import { debounceTimeSafe, Form, FormArrayTemplate, TemplatedFormArray, Types, ExtendedFormGroup, value$ } from '@app/framework'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { distinctUntilChanged } from 'rxjs/operators'; +import { debounceTimeSafe, ExtendedFormGroup, Form, FormArrayTemplate, TemplatedFormArray, Types, value$ } from '@app/framework'; import { FormGroupTemplate, TemplatedFormGroup } from '@app/framework/angular/forms/templated-form-group'; import { AppLanguageDto } from './../services/app-languages.service'; import { LanguageDto } from './../services/languages.service'; diff --git a/frontend/src/app/shared/state/contributors.forms.ts b/frontend/src/app/shared/state/contributors.forms.ts index 1ee61949f..36d0a0656 100644 --- a/frontend/src/app/shared/state/contributors.forms.ts +++ b/frontend/src/app/shared/state/contributors.forms.ts @@ -7,7 +7,7 @@ import { FormControl, Validators } from '@angular/forms'; import { debounceTime, map, shareReplay } from 'rxjs/operators'; -import { Form, hasNoValue$, Types, ExtendedFormGroup, value$ } from '@app/framework'; +import { ExtendedFormGroup, Form, hasNoValue$, Types, value$ } from '@app/framework'; import { AssignContributorDto } from './../services/contributors.service'; import { UserDto } from './../services/users.service'; diff --git a/frontend/src/app/shared/state/languages.forms.ts b/frontend/src/app/shared/state/languages.forms.ts index 9811fbab6..0db61054c 100644 --- a/frontend/src/app/shared/state/languages.forms.ts +++ b/frontend/src/app/shared/state/languages.forms.ts @@ -6,7 +6,7 @@ */ import { FormControl, Validators } from '@angular/forms'; -import { Form, ExtendedFormGroup, value$ } from '@app/framework'; +import { ExtendedFormGroup, Form, value$ } from '@app/framework'; import { AppLanguageDto, UpdateAppLanguageDto } from './../services/app-languages.service'; export class EditLanguageForm extends Form<ExtendedFormGroup, UpdateAppLanguageDto, AppLanguageDto> { diff --git a/frontend/src/app/shared/state/resolvers.ts b/frontend/src/app/shared/state/resolvers.ts index ba7c0e465..b5b83a7c0 100644 --- a/frontend/src/app/shared/state/resolvers.ts +++ b/frontend/src/app/shared/state/resolvers.ts @@ -6,7 +6,7 @@ */ import { Injectable } from '@angular/core'; -import { Observable, from, of, shareReplay } from 'rxjs'; +import { from, Observable, of, shareReplay } from 'rxjs'; import { UIOptions } from '@app/framework'; import { AssetDto, AssetsDto, AssetsService } from './../services/assets.service'; import { ContentDto, ContentsDto, ContentsService } from './../services/contents.service'; diff --git a/frontend/src/app/shared/state/roles.forms.ts b/frontend/src/app/shared/state/roles.forms.ts index dd9051dd9..1d77193ac 100644 --- a/frontend/src/app/shared/state/roles.forms.ts +++ b/frontend/src/app/shared/state/roles.forms.ts @@ -6,7 +6,7 @@ */ import { FormControl, Validators } from '@angular/forms'; -import { Form, hasNoValue$, hasValue$, TemplatedFormArray, ExtendedFormGroup } from '@app/framework'; +import { ExtendedFormGroup, Form, hasNoValue$, hasValue$, TemplatedFormArray } from '@app/framework'; import { CreateRoleDto, RoleDto, UpdateRoleDto } from './../services/roles.service'; export class EditRoleForm extends Form<TemplatedFormArray, UpdateRoleDto, RoleDto> { diff --git a/frontend/src/app/shared/state/rules.forms.ts b/frontend/src/app/shared/state/rules.forms.ts index d4f84126e..53475ffa4 100644 --- a/frontend/src/app/shared/state/rules.forms.ts +++ b/frontend/src/app/shared/state/rules.forms.ts @@ -6,7 +6,7 @@ */ import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'; -import { Form, ExtendedFormGroup, ValidatorsEx } from '@app/framework'; +import { ExtendedFormGroup, Form, ValidatorsEx } from '@app/framework'; import { RuleElementDto } from '../services/rules.service'; export class ActionForm extends Form<any, FormGroup> { diff --git a/frontend/src/app/shared/state/schema-tag-source.ts b/frontend/src/app/shared/state/schema-tag-source.ts index 12ec5b474..9b3ff1092 100644 --- a/frontend/src/app/shared/state/schema-tag-source.ts +++ b/frontend/src/app/shared/state/schema-tag-source.ts @@ -6,7 +6,7 @@ */ import { Injectable } from '@angular/core'; -import { map, shareReplay } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { TagConverter, TagValue } from '@app/framework'; import { SchemaDto } from './../services/schemas.service'; import { SchemasState } from './schemas.state'; @@ -45,7 +45,7 @@ class SchemaConverter implements TagConverter { export class SchemaTagSource { public converter = this.schemasState.schemas.pipe( - map(x => new SchemaConverter(x), shareReplay(1))); + map(x => new SchemaConverter(x))); constructor( readonly schemasState: SchemasState, diff --git a/frontend/src/app/shared/state/schemas.forms.ts b/frontend/src/app/shared/state/schemas.forms.ts index f8e7403ba..234d040de 100644 --- a/frontend/src/app/shared/state/schemas.forms.ts +++ b/frontend/src/app/shared/state/schemas.forms.ts @@ -9,7 +9,7 @@ import { AbstractControl, FormControl, Validators } from '@angular/forms'; import { map } from 'rxjs/operators'; -import { Form, TemplatedFormArray, ExtendedFormGroup, ValidatorsEx, value$ } from '@app/framework'; +import { ExtendedFormGroup, Form, TemplatedFormArray, ValidatorsEx, value$ } from '@app/framework'; import { AddFieldDto, CreateSchemaDto, FieldRule, SchemaDto, SchemaPropertiesDto, SynchronizeSchemaDto, UpdateSchemaDto } from './../services/schemas.service'; import { createProperties, FieldPropertiesDto, FieldPropertiesVisitor } from './../services/schemas.types'; diff --git a/frontend/src/app/shared/state/table-settings.spec.ts b/frontend/src/app/shared/state/table-settings.spec.ts index 70364869b..5ba129e69 100644 --- a/frontend/src/app/shared/state/table-settings.spec.ts +++ b/frontend/src/app/shared/state/table-settings.spec.ts @@ -8,7 +8,7 @@ import { of } from 'rxjs'; import { IMock, It, Mock, Times } from 'typemoq'; import { DateTime, Version } from '@app/framework'; -import { createProperties, MetaFields, RootFieldDto, SchemaDto, TableField, TableSettings, FieldSizes, UIState } from '@app/shared/internal'; +import { createProperties, FieldSizes, MetaFields, RootFieldDto, SchemaDto, TableField, TableSettings, UIState } from '@app/shared/internal'; import { FieldWrappings } from '..'; describe('TableSettings', () => { diff --git a/frontend/src/app/shared/state/template.state.spec.ts b/frontend/src/app/shared/state/template.state.spec.ts new file mode 100644 index 000000000..732dc0c4f --- /dev/null +++ b/frontend/src/app/shared/state/template.state.spec.ts @@ -0,0 +1,67 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { of, throwError } from 'rxjs'; +import { onErrorResumeNext } from 'rxjs/operators'; +import { IMock, It, Mock, Times } from 'typemoq'; +import { DialogService, TemplatesDto, TemplatesService, TemplatesState } from '@app/shared/internal'; +import { createTemplate } from './../services/templates.service.spec'; + +describe('TemplatesState', () => { + const template1 = createTemplate(12); + const template2 = createTemplate(13); + + let dialogs: IMock<DialogService>; + let templatesService: IMock<TemplatesService>; + let templatesState: TemplatesState; + + beforeEach(() => { + dialogs = Mock.ofType<DialogService>(); + + templatesService = Mock.ofType<TemplatesService>(); + templatesState = new TemplatesState(templatesService.object, dialogs.object); + }); + + afterEach(() => { + templatesService.verifyAll(); + }); + + describe('Loading', () => { + it('should load templates', () => { + templatesService.setup(x => x.getTemplates()) + .returns(() => of(new TemplatesDto(2, [template1, template2], {}))).verifiable(); + + templatesState.load().subscribe(); + + expect(templatesState.snapshot.templates).toEqual([template1, template2]); + expect(templatesState.snapshot.isLoaded).toBeTruthy(); + expect(templatesState.snapshot.isLoading).toBeFalsy(); + + dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.never()); + }); + + it('should reset loading state if loading failed', () => { + templatesService.setup(x => x.getTemplates()) + .returns(() => throwError(() => 'Service Error')); + + templatesState.load().pipe(onErrorResumeNext()).subscribe(); + + expect(templatesState.snapshot.isLoading).toBeFalsy(); + }); + + it('should show notification on load if reload is true', () => { + templatesService.setup(x => x.getTemplates()) + .returns(() => of(new TemplatesDto(2, [template1, template2], {}))).verifiable(); + + templatesState.load(true).subscribe(); + + expect().nothing(); + + dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.once()); + }); + }); +}); diff --git a/frontend/src/app/shared/state/templates.state.ts b/frontend/src/app/shared/state/templates.state.ts new file mode 100644 index 000000000..7acfd919f --- /dev/null +++ b/frontend/src/app/shared/state/templates.state.ts @@ -0,0 +1,76 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { finalize, tap } from 'rxjs/operators'; +import { DialogService, shareSubscribed, State } from '@app/framework'; +import { TemplateDto, TemplatesService } from './../services/templates.service'; + +interface Snapshot { + // The current templates. + templates: TemplatesList; + + // Indicates if the templates are loaded. + isLoaded?: boolean; + + // Indicates if the templates are loading. + isLoading?: boolean; + + // Indicates if the user can create new templates. + canCreate?: boolean; +} + +type TemplatesList = ReadonlyArray<TemplateDto>; + +@Injectable() +export class TemplatesState extends State<Snapshot> { + public templates = + this.project(x => x.templates); + + public isLoaded = + this.project(x => x.isLoaded === true); + + public isLoading = + this.project(x => x.isLoading === true); + + constructor( + private readonly templatesService: TemplatesService, + private readonly dialogs: DialogService, + ) { + super({ templates: [] }, 'Templates'); + } + + public load(isReload = false): Observable<any> { + if (isReload) { + this.resetState('Loading Initial'); + } + + return this.loadInternal(isReload); + } + + private loadInternal(isReload: boolean): Observable<any> { + this.next({ isLoading: true }, 'Loading Started'); + + return this.templatesService.getTemplates().pipe( + tap(({ items: templates }) => { + if (isReload) { + this.dialogs.notifyInfo('i18n:templates.reloaded'); + } + + this.next({ + templates, + isLoaded: true, + isLoading: false, + }, 'Loading Success'); + }), + finalize(() => { + this.next({ isLoading: false }, 'Loading Done'); + }), + shareSubscribed(this.dialogs)); + } +} diff --git a/frontend/src/app/shared/state/workflows.forms.ts b/frontend/src/app/shared/state/workflows.forms.ts index 63ea33d27..141baa611 100644 --- a/frontend/src/app/shared/state/workflows.forms.ts +++ b/frontend/src/app/shared/state/workflows.forms.ts @@ -6,7 +6,7 @@ */ import { FormControl, Validators } from '@angular/forms'; -import { Form, hasNoValue$, ExtendedFormGroup } from '@app/framework'; +import { ExtendedFormGroup, Form, hasNoValue$ } from '@app/framework'; import { CreateWorkflowDto } from './../services/workflows.service'; export class AddWorkflowForm extends Form<ExtendedFormGroup, CreateWorkflowDto> { diff --git a/frontend/src/app/theme/_bootstrap.scss b/frontend/src/app/theme/_bootstrap.scss index 5bd4fa597..36f77e8e4 100644 --- a/frontend/src/app/theme/_bootstrap.scss +++ b/frontend/src/app/theme/_bootstrap.scss @@ -62,6 +62,10 @@ .alert-link { color: inherit; } + + a { + color: inherit; + } } .alert-hint { @@ -74,6 +78,12 @@ padding-left: 3rem; position: relative; + &.light { + background: $color-white; + border: 1px solid $color-border; + border-radius: $border-radius; + } + i { @include absolute(1rem, null, null, 1rem); color: $color-theme-brand; @@ -81,6 +91,14 @@ font-weight: normal; vertical-align: text-bottom; } + + .icon-external-link { + color: inherit; + font-size: inherit; + font-weight: normal; + position: static; + vertical-align: baseline; + } } a { diff --git a/frontend/src/app/theme/_common.scss b/frontend/src/app/theme/_common.scss index ba61c811c..cef9270c1 100644 --- a/frontend/src/app/theme/_common.scss +++ b/frontend/src/app/theme/_common.scss @@ -112,6 +112,24 @@ hr { h4 { margin-top: 1rem; } + + pre { + @include text-code; + background: $color-code-background; + margin: .25rem 0; + padding-left: .5rem; + padding-right: 3rem; + } + + table { + width: 100%; + + td, th { + border: 1px solid $color-border; + border-radius: 0; + padding: .25rem .5rem; + } + } } // diff --git a/frontend/src/app/theme/_mixins.scss b/frontend/src/app/theme/_mixins.scss index 6992e815c..3f496c479 100644 --- a/frontend/src/app/theme/_mixins.scss +++ b/frontend/src/app/theme/_mixins.scss @@ -2,7 +2,7 @@ @mixin text-code { font-family: monospace; - font-size: 80%; + font-size: 90%; font-weight: normal; }