Browse Source

Workflow diagram. (#546)

pull/548/head
Sebastian Stehle 6 years ago
committed by GitHub
parent
commit
5f0833161a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      backend/src/Squidex.Web/ApiPermissionAttribute.cs
  2. 19
      backend/src/Squidex.Web/ApiPermissionOrAnonymousAttribute.cs
  3. 8
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppClientsController.cs
  4. 6
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs
  5. 8
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs
  6. 8
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs
  7. 10
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs
  8. 8
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs
  9. 8
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs
  10. 10
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs
  11. 18
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs
  12. 6
      backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs
  13. 8
      backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs
  14. 20
      backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs
  15. 2
      backend/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs
  16. 2
      backend/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs
  17. 4
      backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs
  18. 24
      backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs
  19. 38
      backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs
  20. 22
      backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs
  21. 2
      backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs
  22. 8
      backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs
  23. 2
      backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs
  24. 2
      frontend/app-config/webpack.config.js
  25. 3
      frontend/app/features/settings/declarations.ts
  26. 2
      frontend/app/features/settings/module.ts
  27. 5
      frontend/app/features/settings/pages/workflows/workflow-diagram.component.html
  28. 3
      frontend/app/features/settings/pages/workflows/workflow-diagram.component.scss
  29. 151
      frontend/app/features/settings/pages/workflows/workflow-diagram.component.ts
  30. 109
      frontend/app/features/settings/pages/workflows/workflow.component.html
  31. 6
      frontend/app/features/settings/pages/workflows/workflow.component.ts
  32. 33
      frontend/package-lock.json
  33. 5
      frontend/package.json

2
backend/src/Squidex.Web/ApiPermissionAttribute.cs

@ -15,7 +15,7 @@ using Squidex.Shared;
namespace Squidex.Web
{
public sealed class ApiPermissionAttribute : AuthorizeAttribute, IAsyncActionFilter, IAllowAnonymous
public class ApiPermissionAttribute : AuthorizeAttribute, IAsyncActionFilter
{
private readonly string[] permissionIds;

19
backend/src/Squidex.Web/ApiPermissionOrAnonymousAttribute.cs

@ -0,0 +1,19 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Authorization;
namespace Squidex.Web
{
public class ApiPermissionOrAnonymousAttribute : ApiPermissionAttribute, IAllowAnonymous
{
public ApiPermissionOrAnonymousAttribute(params string[] ids)
: base(ids)
{
}
}
}

8
backend/src/Squidex/Areas/Api/Controllers/Apps/AppClientsController.cs

@ -42,7 +42,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpGet]
[Route("apps/{app}/clients/")]
[ProducesResponseType(typeof(ClientsDto), 200)]
[ApiPermission(Permissions.AppClientsRead)]
[ApiPermissionOrAnonymous(Permissions.AppClientsRead)]
[ApiCosts(0)]
public IActionResult GetClients(string app)
{
@ -73,7 +73,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPost]
[Route("apps/{app}/clients/")]
[ProducesResponseType(typeof(ClientsDto), 201)]
[ApiPermission(Permissions.AppClientsCreate)]
[ApiPermissionOrAnonymous(Permissions.AppClientsCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostClient(string app, [FromBody] CreateClientDto request)
{
@ -101,7 +101,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPut]
[Route("apps/{app}/clients/{id}/")]
[ProducesResponseType(typeof(ClientsDto), 200)]
[ApiPermission(Permissions.AppClientsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppClientsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutClient(string app, string id, [FromBody] UpdateClientDto request)
{
@ -127,7 +127,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpDelete]
[Route("apps/{app}/clients/{id}/")]
[ProducesResponseType(typeof(ClientsDto), 200)]
[ApiPermission(Permissions.AppClientsDelete)]
[ApiPermissionOrAnonymous(Permissions.AppClientsDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteClient(string app, string id)
{

6
backend/src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs

@ -48,7 +48,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpGet]
[Route("apps/{app}/contributors/")]
[ProducesResponseType(typeof(ContributorsDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public IActionResult GetContributors(string app)
{
@ -75,7 +75,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPost]
[Route("apps/{app}/contributors/")]
[ProducesResponseType(typeof(ContributorsDto), 201)]
[ApiPermission(Permissions.AppContributorsAssign)]
[ApiPermissionOrAnonymous(Permissions.AppContributorsAssign)]
[ApiCosts(1)]
public async Task<IActionResult> PostContributor(string app, [FromBody] AssignContributorDto request)
{
@ -98,7 +98,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpDelete]
[Route("apps/{app}/contributors/{id}/")]
[ProducesResponseType(typeof(ContributorsDto), 200)]
[ApiPermission(Permissions.AppContributorsRevoke)]
[ApiPermissionOrAnonymous(Permissions.AppContributorsRevoke)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteContributor(string app, string id)
{

8
backend/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs

@ -42,7 +42,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpGet]
[Route("apps/{app}/languages/")]
[ProducesResponseType(typeof(AppLanguagesDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public IActionResult GetLanguages(string app)
{
@ -69,7 +69,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPost]
[Route("apps/{app}/languages/")]
[ProducesResponseType(typeof(AppLanguagesDto), 201)]
[ApiPermission(Permissions.AppLanguagesCreate)]
[ApiPermissionOrAnonymous(Permissions.AppLanguagesCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostLanguage(string app, [FromBody] AddLanguageDto request)
{
@ -94,7 +94,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPut]
[Route("apps/{app}/languages/{language}/")]
[ProducesResponseType(typeof(AppLanguagesDto), 200)]
[ApiPermission(Permissions.AppLanguagesUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppLanguagesUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutLanguage(string app, string language, [FromBody] UpdateLanguageDto request)
{
@ -118,7 +118,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpDelete]
[Route("apps/{app}/languages/{language}/")]
[ProducesResponseType(typeof(AppLanguagesDto), 200)]
[ApiPermission(Permissions.AppLanguagesDelete)]
[ApiPermissionOrAnonymous(Permissions.AppLanguagesDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteLanguage(string app, string language)
{

8
backend/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs

@ -43,7 +43,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpGet]
[Route("apps/{app}/patterns/")]
[ProducesResponseType(typeof(PatternsDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public IActionResult GetPatterns(string app)
{
@ -70,7 +70,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPost]
[Route("apps/{app}/patterns/")]
[ProducesResponseType(typeof(PatternsDto), 201)]
[ApiPermission(Permissions.AppPatternsCreate)]
[ApiPermissionOrAnonymous(Permissions.AppPatternsCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostPattern(string app, [FromBody] UpdatePatternDto request)
{
@ -95,7 +95,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPut]
[Route("apps/{app}/patterns/{id}/")]
[ProducesResponseType(typeof(PatternsDto), 200)]
[ApiPermission(Permissions.AppPatternsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppPatternsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutPattern(string app, Guid id, [FromBody] UpdatePatternDto request)
{
@ -121,7 +121,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpDelete]
[Route("apps/{app}/patterns/{id}/")]
[ProducesResponseType(typeof(PatternsDto), 200)]
[ApiPermission(Permissions.AppPatternsDelete)]
[ApiPermissionOrAnonymous(Permissions.AppPatternsDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeletePattern(string app, Guid id)
{

10
backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs

@ -43,7 +43,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpGet]
[Route("apps/{app}/roles/")]
[ProducesResponseType(typeof(RolesDto), 200)]
[ApiPermission(Permissions.AppRolesRead)]
[ApiPermissionOrAnonymous(Permissions.AppRolesRead)]
[ApiCosts(0)]
public IActionResult GetRoles(string app)
{
@ -68,7 +68,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpGet]
[Route("apps/{app}/roles/permissions")]
[ProducesResponseType(typeof(string[]), 200)]
[ApiPermission(Permissions.AppRolesRead)]
[ApiPermissionOrAnonymous(Permissions.AppRolesRead)]
[ApiCosts(0)]
public IActionResult GetPermissions(string app)
{
@ -95,7 +95,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPost]
[Route("apps/{app}/roles/")]
[ProducesResponseType(typeof(RolesDto), 201)]
[ApiPermission(Permissions.AppRolesCreate)]
[ApiPermissionOrAnonymous(Permissions.AppRolesCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostRole(string app, [FromBody] AddRoleDto request)
{
@ -120,7 +120,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPut]
[Route("apps/{app}/roles/{roleName}/")]
[ProducesResponseType(typeof(RolesDto), 200)]
[ApiPermission(Permissions.AppRolesUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppRolesUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutRole(string app, string roleName, [FromBody] UpdateRoleDto request)
{
@ -144,7 +144,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpDelete]
[Route("apps/{app}/roles/{roleName}/")]
[ProducesResponseType(typeof(RolesDto), 200)]
[ApiPermission(Permissions.AppRolesDelete)]
[ApiPermissionOrAnonymous(Permissions.AppRolesDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteRole(string app, string roleName)
{

8
backend/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs

@ -44,7 +44,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpGet]
[Route("apps/{app}/workflows/")]
[ProducesResponseType(typeof(WorkflowsDto), 200)]
[ApiPermission(Permissions.AppWorkflowsRead)]
[ApiPermissionOrAnonymous(Permissions.AppWorkflowsRead)]
[ApiCosts(0)]
public IActionResult GetWorkflows(string app)
{
@ -71,7 +71,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPost]
[Route("apps/{app}/workflows/")]
[ProducesResponseType(typeof(WorkflowsDto), 200)]
[ApiPermission(Permissions.AppWorkflowsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppWorkflowsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PostWorkflow(string app, [FromBody] AddWorkflowDto request)
{
@ -96,7 +96,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPut]
[Route("apps/{app}/workflows/{id}")]
[ProducesResponseType(typeof(WorkflowsDto), 200)]
[ApiPermission(Permissions.AppWorkflowsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppWorkflowsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutWorkflow(string app, Guid id, [FromBody] UpdateWorkflowDto request)
{
@ -119,7 +119,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpDelete]
[Route("apps/{app}/workflows/{id}")]
[ProducesResponseType(typeof(WorkflowsDto), 200)]
[ApiPermission(Permissions.AppWorkflowsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppWorkflowsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteWorkflow(string app, Guid id)
{

8
backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs

@ -152,7 +152,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPut]
[Route("apps/{app}/")]
[ProducesResponseType(typeof(AppDto), 200)]
[ApiPermission(Permissions.AppUpdateGeneral)]
[ApiPermissionOrAnonymous(Permissions.AppUpdateGeneral)]
[ApiCosts(0)]
public async Task<IActionResult> UpdateApp(string app, [FromBody] UpdateAppDto request)
{
@ -173,7 +173,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpPost]
[Route("apps/{app}/image")]
[ProducesResponseType(typeof(AppDto), 200)]
[ApiPermission(Permissions.AppUpdateImage)]
[ApiPermissionOrAnonymous(Permissions.AppUpdateImage)]
[ApiCosts(0)]
public async Task<IActionResult> UploadImage(string app, IFormFile file)
{
@ -264,7 +264,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[HttpDelete]
[Route("apps/{app}/image")]
[ProducesResponseType(typeof(AppDto), 200)]
[ApiPermission(Permissions.AppUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppUpdate)]
[ApiCosts(0)]
public async Task<IActionResult> DeleteImage(string app)
{
@ -283,7 +283,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
/// </returns>
[HttpDelete]
[Route("apps/{app}/")]
[ApiPermission(Permissions.AppDelete)]
[ApiPermissionOrAnonymous(Permissions.AppDelete)]
[ApiCosts(0)]
public async Task<IActionResult> DeleteApp(string app)
{

10
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs

@ -48,7 +48,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[HttpGet]
[Route("apps/{app}/assets/folders", Order = -1)]
[ProducesResponseType(typeof(AssetsDto), 200)]
[ApiPermission(Permissions.AppAssetsRead)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetAssetFolders(string app, [FromQuery] Guid parentId)
{
@ -79,7 +79,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[Route("apps/{app}/assets/folders", Order = -1)]
[ProducesResponseType(typeof(AssetDto), 201)]
[AssetRequestSizeLimit]
[ApiPermission(Permissions.AppAssetsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PostAssetFolder(string app, [FromBody] CreateAssetFolderDto request)
{
@ -105,7 +105,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[Route("apps/{app}/assets/folders/{id}/", Order = -1)]
[ProducesResponseType(typeof(AssetDto), 200)]
[AssetRequestSizeLimit]
[ApiPermission(Permissions.AppAssetsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutAssetFolder(string app, Guid id, [FromBody] RenameAssetFolderDto request)
{
@ -130,7 +130,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[Route("apps/{app}/assets/folders/{id}/parent", Order = -1)]
[ProducesResponseType(typeof(AssetDto), 200)]
[AssetRequestSizeLimit]
[ApiPermission(Permissions.AppAssetsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutAssetFolderParent(string app, Guid id, [FromBody] MoveAssetItemDto request)
{
@ -152,7 +152,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// </returns>
[HttpDelete]
[Route("apps/{app}/assets/folders/{id}/", Order = -1)]
[ApiPermission(Permissions.AppAssetsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteAssetFolder(string app, Guid id)
{

18
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs

@ -64,7 +64,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[HttpGet]
[Route("apps/{app}/assets/tags")]
[ProducesResponseType(typeof(Dictionary<string, int>), 200)]
[ApiPermission(Permissions.AppAssetsRead)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetTags(string app)
{
@ -92,7 +92,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[HttpGet]
[Route("apps/{app}/assets/")]
[ProducesResponseType(typeof(AssetsDto), 200)]
[ApiPermission(Permissions.AppAssetsRead)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetAssets(string app, [FromQuery] Guid? parentId, [FromQuery] string? ids = null, [FromQuery] string? q = null)
{
@ -121,7 +121,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[HttpPost]
[Route("apps/{app}/assets/query")]
[ProducesResponseType(typeof(AssetsDto), 200)]
[ApiPermission(Permissions.AppAssetsRead)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetAssetsPost(string app, [FromBody] QueryDto query)
{
@ -147,7 +147,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[HttpGet]
[Route("apps/{app}/assets/{id}/")]
[ProducesResponseType(typeof(AssetDto), 200)]
[ApiPermission(Permissions.AppAssetsRead)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetAsset(string app, Guid id)
{
@ -184,7 +184,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[Route("apps/{app}/assets/")]
[ProducesResponseType(typeof(AssetDto), 201)]
[AssetRequestSizeLimit]
[ApiPermission(Permissions.AppAssetsCreate)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostAsset(string app, [FromQuery] Guid parentId, IFormFile file)
{
@ -214,7 +214,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[HttpPut]
[Route("apps/{app}/assets/{id}/content/")]
[ProducesResponseType(typeof(AssetDto), 200)]
[ApiPermission(Permissions.AppAssetsUpload)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpload)]
[ApiCosts(1)]
public async Task<IActionResult> PutAssetContent(string app, Guid id, IFormFile file)
{
@ -242,7 +242,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[Route("apps/{app}/assets/{id}/")]
[ProducesResponseType(typeof(AssetDto), 200)]
[AssetRequestSizeLimit]
[ApiPermission(Permissions.AppAssetsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutAsset(string app, Guid id, [FromBody] AnnotateAssetDto request)
{
@ -267,7 +267,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[Route("apps/{app}/assets/{id}/parent")]
[ProducesResponseType(typeof(AssetDto), 200)]
[AssetRequestSizeLimit]
[ApiPermission(Permissions.AppAssetsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutAssetParent(string app, Guid id, [FromBody] MoveAssetItemDto request)
{
@ -289,7 +289,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// </returns>
[HttpDelete]
[Route("apps/{app}/assets/{id}/")]
[ApiPermission(Permissions.AppAssetsDelete)]
[ApiPermissionOrAnonymous(Permissions.AppAssetsDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteAsset(string app, Guid id)
{

6
backend/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs

@ -44,7 +44,7 @@ namespace Squidex.Areas.Api.Controllers.Backups
[HttpGet]
[Route("apps/{app}/backups/")]
[ProducesResponseType(typeof(BackupJobsDto), 200)]
[ApiPermission(Permissions.AppBackupsRead)]
[ApiPermissionOrAnonymous(Permissions.AppBackupsRead)]
[ApiCosts(0)]
public async Task<IActionResult> GetBackups(string app)
{
@ -66,7 +66,7 @@ namespace Squidex.Areas.Api.Controllers.Backups
[HttpPost]
[Route("apps/{app}/backups/")]
[ProducesResponseType(typeof(List<BackupJobDto>), 200)]
[ApiPermission(Permissions.AppBackupsCreate)]
[ApiPermissionOrAnonymous(Permissions.AppBackupsCreate)]
[ApiCosts(0)]
public IActionResult PostBackup(string app)
{
@ -87,7 +87,7 @@ namespace Squidex.Areas.Api.Controllers.Backups
[HttpDelete]
[Route("apps/{app}/backups/{id}")]
[ProducesResponseType(typeof(List<BackupJobDto>), 200)]
[ApiPermission(Permissions.AppBackupsDelete)]
[ApiPermissionOrAnonymous(Permissions.AppBackupsDelete)]
[ApiCosts(0)]
public async Task<IActionResult> DeleteBackup(string app, Guid id)
{

8
backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs

@ -49,7 +49,7 @@ namespace Squidex.Areas.Api.Controllers.Comments
[HttpGet]
[Route("apps/{app}/comments/{commentsId}")]
[ProducesResponseType(typeof(CommentsDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetComments(string app, string commentsId, [FromQuery] long version = EtagVersion.Any)
{
@ -79,7 +79,7 @@ namespace Squidex.Areas.Api.Controllers.Comments
[HttpPost]
[Route("apps/{app}/comments/{commentsId}")]
[ProducesResponseType(typeof(CommentDto), 201)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> PostComment(string app, string commentsId, [FromBody] UpsertCommentDto request)
{
@ -106,7 +106,7 @@ namespace Squidex.Areas.Api.Controllers.Comments
/// </returns>
[HttpPut]
[Route("apps/{app}/comments/{commentsId}/{commentId}")]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> PutComment(string app, string commentsId, Guid commentId, [FromBody] UpsertCommentDto request)
{
@ -127,7 +127,7 @@ namespace Squidex.Areas.Api.Controllers.Comments
/// </returns>
[HttpDelete]
[Route("apps/{app}/comments/{commentsId}/{commentId}")]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> DeleteComment(string app, string commentsId, Guid commentId)
{

20
backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs

@ -268,7 +268,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
/// </remarks>
[HttpGet]
[Route("content/{app}/{name}/{id}/{version}/")]
[ApiPermission(Permissions.AppContentsRead)]
[ApiPermissionOrAnonymous(Permissions.AppContentsRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetContentVersion(string app, string name, Guid id, int version)
{
@ -297,7 +297,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPost]
[Route("content/{app}/{name}/")]
[ProducesResponseType(typeof(ContentsDto), 201)]
[ApiPermission(Permissions.AppContentsCreate)]
[ApiPermissionOrAnonymous(Permissions.AppContentsCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostContent(string app, string name, [FromBody] NamedContentData request, [FromQuery] bool publish = false)
{
@ -325,7 +325,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPost]
[Route("content/{app}/{name}/import")]
[ProducesResponseType(typeof(BulkResultDto[]), 200)]
[ApiPermission(Permissions.AppContentsCreate)]
[ApiPermissionOrAnonymous(Permissions.AppContentsCreate)]
[ApiCosts(5)]
public async Task<IActionResult> PostContents(string app, string name, [FromBody] ImportContentsDto request)
{
@ -356,7 +356,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPost]
[Route("content/{app}/{name}/bulk")]
[ProducesResponseType(typeof(BulkResultDto[]), 200)]
[ApiPermission(Permissions.AppContents)]
[ApiPermissionOrAnonymous(Permissions.AppContents)]
[ApiCosts(5)]
public async Task<IActionResult> BulkContents(string app, string name, [FromBody] BulkUpdateDto request)
{
@ -388,7 +388,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPut]
[Route("content/{app}/{name}/{id}/")]
[ProducesResponseType(typeof(ContentsDto), 200)]
[ApiPermission(Permissions.AppContentsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppContentsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutContent(string app, string name, Guid id, [FromBody] NamedContentData request)
{
@ -417,7 +417,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPatch]
[Route("content/{app}/{name}/{id}/")]
[ProducesResponseType(typeof(ContentsDto), 200)]
[ApiPermission(Permissions.AppContentsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppContentsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PatchContent(string app, string name, Guid id, [FromBody] NamedContentData request)
{
@ -446,7 +446,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPut]
[Route("content/{app}/{name}/{id}/status/")]
[ProducesResponseType(typeof(ContentsDto), 200)]
[ApiPermission(Permissions.AppContentsUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppContentsUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutContentStatus(string app, string name, Guid id, ChangeStatusDto request)
{
@ -473,7 +473,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPost]
[Route("content/{app}/{name}/{id}/draft/")]
[ProducesResponseType(typeof(ContentsDto), 200)]
[ApiPermission(Permissions.AppContentsVersionCreate)]
[ApiPermissionOrAnonymous(Permissions.AppContentsVersionCreate)]
[ApiCosts(1)]
public async Task<IActionResult> CreateDraft(string app, string name, Guid id)
{
@ -500,7 +500,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpDelete]
[Route("content/{app}/{name}/{id}/draft/")]
[ProducesResponseType(typeof(ContentsDto), 200)]
[ApiPermission(Permissions.AppContentsDelete)]
[ApiPermissionOrAnonymous(Permissions.AppContentsDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteVersion(string app, string name, Guid id)
{
@ -526,7 +526,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
/// </remarks>
[HttpDelete]
[Route("content/{app}/{name}/{id}/")]
[ApiPermission(Permissions.AppContentsDelete)]
[ApiPermissionOrAnonymous(Permissions.AppContentsDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteContent(string app, string name, Guid id)
{

2
backend/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs

@ -42,7 +42,7 @@ namespace Squidex.Areas.Api.Controllers.History
[HttpGet]
[Route("apps/{app}/history/")]
[ProducesResponseType(typeof(HistoryEventDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0.1)]
public async Task<IActionResult> GetHistory(string app, string channel)
{

2
backend/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs

@ -68,7 +68,7 @@ namespace Squidex.Areas.Api.Controllers.Ping
/// </remarks>
[HttpGet]
[Route("ping/{app}/")]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public IActionResult GetAppPing(string app)
{

4
backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs

@ -45,7 +45,7 @@ namespace Squidex.Areas.Api.Controllers.Plans
[HttpGet]
[Route("apps/{app}/plans/")]
[ProducesResponseType(typeof(AppPlansDto), 200)]
[ApiPermission(Permissions.AppPlansRead)]
[ApiPermissionOrAnonymous(Permissions.AppPlansRead)]
[ApiCosts(0)]
public IActionResult GetPlans(string app)
{
@ -74,7 +74,7 @@ namespace Squidex.Areas.Api.Controllers.Plans
[HttpPut]
[Route("apps/{app}/plan/")]
[ProducesResponseType(typeof(PlanChangedDto), 200)]
[ApiPermission(Permissions.AppPlansChange)]
[ApiPermissionOrAnonymous(Permissions.AppPlansChange)]
[ApiCosts(0)]
public async Task<IActionResult> PutPlan(string app, [FromBody] ChangePlanDto request)
{

24
backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs

@ -85,7 +85,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpGet]
[Route("apps/{app}/rules/")]
[ProducesResponseType(typeof(RulesDto), 200)]
[ApiPermission(Permissions.AppRulesRead)]
[ApiPermissionOrAnonymous(Permissions.AppRulesRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetRules(string app)
{
@ -114,7 +114,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpPost]
[Route("apps/{app}/rules/")]
[ProducesResponseType(typeof(RuleDto), 201)]
[ApiPermission(Permissions.AppRulesCreate)]
[ApiPermissionOrAnonymous(Permissions.AppRulesCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostRule(string app, [FromBody] CreateRuleDto request)
{
@ -135,7 +135,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpDelete]
[Route("apps/{app}/rules/run")]
[ProducesResponseType(204)]
[ApiPermission(Permissions.AppRulesEvents)]
[ApiPermissionOrAnonymous(Permissions.AppRulesEvents)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteRuleRun(string app)
{
@ -158,7 +158,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpPut]
[Route("apps/{app}/rules/{id}/")]
[ProducesResponseType(typeof(RuleDto), 200)]
[ApiPermission(Permissions.AppRulesUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppRulesUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutRule(string app, Guid id, [FromBody] UpdateRuleDto request)
{
@ -181,7 +181,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpPut]
[Route("apps/{app}/rules/{id}/enable/")]
[ProducesResponseType(typeof(RuleDto), 200)]
[ApiPermission(Permissions.AppRulesDisable)]
[ApiPermissionOrAnonymous(Permissions.AppRulesDisable)]
[ApiCosts(1)]
public async Task<IActionResult> EnableRule(string app, Guid id)
{
@ -204,7 +204,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpPut]
[Route("apps/{app}/rules/{id}/disable/")]
[ProducesResponseType(typeof(RuleDto), 200)]
[ApiPermission(Permissions.AppRulesDisable)]
[ApiPermissionOrAnonymous(Permissions.AppRulesDisable)]
[ApiCosts(1)]
public async Task<IActionResult> DisableRule(string app, Guid id)
{
@ -226,7 +226,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
/// </returns>
[HttpPut]
[Route("apps/{app}/rules/{id}/trigger/")]
[ApiPermission(Permissions.AppRulesEvents)]
[ApiPermissionOrAnonymous(Permissions.AppRulesEvents)]
[ApiCosts(1)]
public async Task<IActionResult> TriggerRule(string app, Guid id)
{
@ -248,7 +248,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpPut]
[Route("apps/{app}/rules/{id}/run")]
[ProducesResponseType(204)]
[ApiPermission(Permissions.AppRulesEvents)]
[ApiPermissionOrAnonymous(Permissions.AppRulesEvents)]
[ApiCosts(1)]
public async Task<IActionResult> PutRuleRun(string app, Guid id)
{
@ -268,7 +268,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
/// </returns>
[HttpDelete]
[Route("apps/{app}/rules/{id}/")]
[ApiPermission(Permissions.AppRulesDelete)]
[ApiPermissionOrAnonymous(Permissions.AppRulesDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteRule(string app, Guid id)
{
@ -291,7 +291,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
[HttpGet]
[Route("apps/{app}/rules/events/")]
[ProducesResponseType(typeof(RuleEventsDto), 200)]
[ApiPermission(Permissions.AppRulesRead)]
[ApiPermissionOrAnonymous(Permissions.AppRulesRead)]
[ApiCosts(0)]
public async Task<IActionResult> GetEvents(string app, [FromQuery] Guid? ruleId = null, [FromQuery] int skip = 0, [FromQuery] int take = 20)
{
@ -313,7 +313,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
/// </returns>
[HttpPut]
[Route("apps/{app}/rules/events/{id}/")]
[ApiPermission(Permissions.AppRulesEvents)]
[ApiPermissionOrAnonymous(Permissions.AppRulesEvents)]
[ApiCosts(0)]
public async Task<IActionResult> PutEvent(string app, Guid id)
{
@ -340,7 +340,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
/// </returns>
[HttpDelete]
[Route("apps/{app}/rules/events/{id}/")]
[ApiPermission(Permissions.AppRulesEvents)]
[ApiPermissionOrAnonymous(Permissions.AppRulesEvents)]
[ApiCosts(0)]
public async Task<IActionResult> DeleteEvent(string app, Guid id)
{

38
backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs

@ -42,7 +42,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPost]
[Route("apps/{app}/schemas/{name}/fields/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 201)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PostField(string app, string name, [FromBody] AddFieldDto request)
{
@ -69,7 +69,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPost]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 201)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PostNestedField(string app, string name, long parentId, [FromBody] AddFieldDto request)
{
@ -94,7 +94,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/ui/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutSchemaUIFields(string app, string name, [FromBody] ConfigureUIFieldsDto request)
{
@ -119,7 +119,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/ordering/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutSchemaFieldOrdering(string app, string name, [FromBody] ReorderFieldsDto request)
{
@ -145,7 +145,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/ordering/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutNestedFieldOrdering(string app, string name, long parentId, [FromBody] ReorderFieldsDto request)
{
@ -171,7 +171,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{id:long}/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutField(string app, string name, long id, [FromBody] UpdateFieldDto request)
{
@ -198,7 +198,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutNestedField(string app, string name, long parentId, long id, [FromBody] UpdateFieldDto request)
{
@ -225,7 +225,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{id:long}/lock/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> LockField(string app, string name, long id)
{
@ -253,7 +253,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/lock/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> LockNestedField(string app, string name, long parentId, long id)
{
@ -280,7 +280,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{id:long}/hide/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> HideField(string app, string name, long id)
{
@ -308,7 +308,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/hide/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> HideNestedField(string app, string name, long parentId, long id)
{
@ -335,7 +335,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{id:long}/show/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> ShowField(string app, string name, long id)
{
@ -363,7 +363,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/show/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> ShowNestedField(string app, string name, long parentId, long id)
{
@ -390,7 +390,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{id:long}/enable/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> EnableField(string app, string name, long id)
{
@ -418,7 +418,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/enable/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> EnableNestedField(string app, string name, long parentId, long id)
{
@ -445,7 +445,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{id:long}/disable/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> DisableField(string app, string name, long id)
{
@ -473,7 +473,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/disable/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> DisableNestedField(string app, string name, long parentId, long id)
{
@ -498,7 +498,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpDelete]
[Route("apps/{app}/schemas/{name}/fields/{id:long}/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteField(string app, string name, long id)
{
@ -524,7 +524,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpDelete]
[Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteNestedField(string app, string name, long parentId, long id)
{

22
backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs

@ -44,7 +44,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpGet]
[Route("apps/{app}/schemas/")]
[ProducesResponseType(typeof(SchemasDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetSchemas(string app)
{
@ -72,7 +72,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpGet]
[Route("apps/{app}/schemas/{name}/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetSchema(string app, string name)
{
@ -115,7 +115,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPost]
[Route("apps/{app}/schemas/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 201)]
[ApiPermission(Permissions.AppSchemasCreate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostSchema(string app, [FromBody] CreateSchemaDto request)
{
@ -140,7 +140,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutSchema(string app, string name, [FromBody] UpdateSchemaDto request)
{
@ -165,7 +165,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/sync")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutSchemaSync(string app, string name, [FromBody] SynchronizeSchemaDto request)
{
@ -189,7 +189,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/category")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutCategory(string app, string name, [FromBody] ChangeCategoryDto request)
{
@ -213,7 +213,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/preview-urls")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasUpdate)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasUpdate)]
[ApiCosts(1)]
public async Task<IActionResult> PutPreviewUrls(string app, string name, [FromBody] ConfigurePreviewUrlsDto request)
{
@ -238,7 +238,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/scripts/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasScripts)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasScripts)]
[ApiCosts(1)]
public async Task<IActionResult> PutScripts(string app, string name, [FromBody] SchemaScriptsDto request)
{
@ -261,7 +261,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/publish/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasPublish)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasPublish)]
[ApiCosts(1)]
public async Task<IActionResult> PublishSchema(string app, string name)
{
@ -284,7 +284,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
[HttpPut]
[Route("apps/{app}/schemas/{name}/unpublish/")]
[ProducesResponseType(typeof(SchemaDetailsDto), 200)]
[ApiPermission(Permissions.AppSchemasPublish)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasPublish)]
[ApiCosts(1)]
public async Task<IActionResult> UnpublishSchema(string app, string name)
{
@ -306,7 +306,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
/// </returns>
[HttpDelete]
[Route("apps/{app}/schemas/{name}/")]
[ApiPermission(Permissions.AppSchemasDelete)]
[ApiPermissionOrAnonymous(Permissions.AppSchemasDelete)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteSchema(string app, string name)
{

2
backend/src/Squidex/Areas/Api/Controllers/Search/SearchController.cs

@ -42,7 +42,7 @@ namespace Squidex.Areas.Api.Controllers.Search
[HttpGet]
[Route("apps/{app}/search/")]
[ProducesResponseType(typeof(SearchResultDto[]), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetSchemas(string app, [FromQuery] string? query = null)
{

8
backend/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs

@ -66,7 +66,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics
[HttpGet]
[Route("apps/{app}/usages/log/")]
[ProducesResponseType(typeof(LogDownloadDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public IActionResult GetLog(string app)
{
@ -93,7 +93,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics
[HttpGet]
[Route("apps/{app}/usages/calls/{fromDate}/{toDate}/")]
[ProducesResponseType(typeof(CallsUsageDtoDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetUsages(string app, DateTime fromDate, DateTime toDate)
{
@ -122,7 +122,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics
[HttpGet]
[Route("apps/{app}/usages/storage/today/")]
[ProducesResponseType(typeof(CurrentStorageDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetCurrentStorageSize(string app)
{
@ -149,7 +149,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics
[HttpGet]
[Route("apps/{app}/usages/storage/{fromDate}/{toDate}/")]
[ProducesResponseType(typeof(StorageUsagePerDateDto[]), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetStorageSizes(string app, DateTime fromDate, DateTime toDate)
{

2
backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs

@ -40,7 +40,7 @@ namespace Squidex.Areas.Api.Controllers.Translations
[HttpPost]
[Route("apps/{app}/translations/")]
[ProducesResponseType(typeof(TranslationDto), 200)]
[ApiPermission(Permissions.AppCommon)]
[ApiPermissionOrAnonymous(Permissions.AppCommon)]
[ApiCosts(0)]
public async Task<IActionResult> GetLanguages(string app, [FromBody] TranslateDto request)
{

2
frontend/app-config/webpack.config.js

@ -227,6 +227,8 @@ module.exports = function (env) {
{ from: './node_modules/font-awesome/css/font-awesome.min.css', to: 'dependencies/font-awesome/css/font-awesome.min.css' },
{ from: './node_modules/font-awesome/fonts', to: 'dependencies/font-awesome/fonts' },
{ from: './node_modules/vis-network/standalone/umd/vis-network.min.js', to: 'dependencies/vis-network.min.js' },
],
}),
],

3
frontend/app/features/settings/declarations.ts

@ -27,8 +27,9 @@ export * from './pages/roles/role-add-form.component';
export * from './pages/roles/role.component';
export * from './pages/roles/roles-page.component';
export * from './pages/workflows/workflow-add-form.component';
export * from './pages/workflows/workflow-diagram.component';
export * from './pages/workflows/workflow-step.component';
export * from './pages/workflows/workflow-transition.component';
export * from './pages/workflows/workflow.component';
export * from './pages/workflows/workflows-page.component';
export * from './pages/workflows/workflow.component';
export * from './settings-area.component';

2
frontend/app/features/settings/module.ts

@ -11,6 +11,7 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HelpComponent, HistoryComponent, SqxFrameworkModule, SqxSharedModule } from '@app/shared';
import { BackupComponent, BackupsPageComponent, ClientAddFormComponent, ClientComponent, ClientConnectFormComponent, ClientsPageComponent, ContributorAddFormComponent, ContributorComponent, ContributorsPageComponent, ImportContributorsDialogComponent, LanguageAddFormComponent, LanguageComponent, LanguagesPageComponent, MorePageComponent, PatternComponent, PatternsPageComponent, PlanComponent, PlansPageComponent, RoleAddFormComponent, RoleComponent, RolesPageComponent, SettingsAreaComponent, WorkflowAddFormComponent, WorkflowComponent, WorkflowsPageComponent, WorkflowStepComponent, WorkflowTransitionComponent } from './declarations';
import { WorkflowDiagramComponent } from './pages/workflows/workflow-diagram.component';
const routes: Routes = [
{
@ -195,6 +196,7 @@ const routes: Routes = [
SettingsAreaComponent,
WorkflowAddFormComponent,
WorkflowComponent,
WorkflowDiagramComponent,
WorkflowsPageComponent,
WorkflowStepComponent,
WorkflowTransitionComponent

5
frontend/app/features/settings/pages/workflows/workflow-diagram.component.html

@ -0,0 +1,5 @@
<sqx-list-view [isLoaded]="isLoaded">
<ng-container content>
<div #chartContainer></div>
</ng-container>
</sqx-list-view>

3
frontend/app/features/settings/pages/workflows/workflow-diagram.component.scss

@ -0,0 +1,3 @@
div {
height: 500px;
}

151
frontend/app/features/settings/pages/workflows/workflow-diagram.component.ts

@ -0,0 +1,151 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core';
import { ResourceLoaderService, WorkflowDto } from '@app/shared';
declare var vis: any;
@Component({
selector: 'sqx-workflow-diagram',
styleUrls: ['./workflow-diagram.component.scss'],
templateUrl: './workflow-diagram.component.html'
})
export class WorkflowDiagramComponent implements AfterViewInit, OnDestroy, OnChanges {
private network: any;
@ViewChild('chartContainer', { static: false })
public chartContainer: ElementRef;
@Input()
public workflow: WorkflowDto;
public isLoaded = false;
constructor(
private readonly resourceLoader: ResourceLoaderService
) {
}
public ngOnDestroy() {
this.network?.destroy();
}
public ngOnChanges() {
this.updateNetwork();
}
public ngAfterViewInit() {
this.updateNetwork();
}
private updateNetwork() {
if (this.chartContainer?.nativeElement && this.workflow) {
this.resourceLoader.loadLocalScript('dependencies/vis-network.min.js')
.then(() => {
this.network?.destroy();
const nodes = new vis.DataSet();
for (const step of this.workflow.steps) {
let label = `<b>${step.name}</b>`;
if (step.noUpdate) {
label += `\nPrevent updates`;
if (step.noUpdateExpression) {
label += `\nwhen (${step.noUpdateExpression})`;
}
if (step.noUpdateRoles && step.noUpdateRoles.length > 0) {
label += `\nfor ${step.noUpdateRoles.join(', ')}`;
}
}
if (step.name === 'Published') {
label += `\nAvailable in the API`;
}
const node: any = { id: step.name, label, color: step.color };
nodes.add(node);
}
if (this.workflow.initial) {
nodes.add({ id: 0, color: '#000', label: 'Start', shape: 'dot', size: 3 });
}
const edges = new vis.DataSet();
for (const transition of this.workflow.transitions) {
let label = '';
if (transition.expression) {
label += `\nwhen (${transition.expression})`;
}
if (transition.roles && transition.roles.length > 0) {
label += `\nfor ${transition.roles.join(', ')}`;
}
const edge: any = { ...transition, label };
edges.add(edge);
}
if (this.workflow.initial) {
edges.add({ from: 0, to: this.workflow.initial });
}
this.network = new vis.Network(this.chartContainer.nativeElement, { edges, nodes }, GRAPH_OPTIONS);
this.network.stabilize();
this.network.fit();
this.isLoaded = true;
});
}
}
}
const GRAPH_OPTIONS = {
nodes: {
borderWidth: 2,
font: {
multi: true, align: 'left',
ital: {
size: 16
},
bold: {
size: 20
},
size: 16
},
shape: 'dot',
shadow: true
},
edges: {
arrows: 'to',
font: {
multi: true,
ital: {
size: 16
},
size: 16
},
color: 'gray'
},
layout: {
randomSeed: 2
},
physics: {
enabled: false,
repulsion: {
nodeDistance: 300
},
solver: 'repulsion'
}
};

109
frontend/app/features/settings/pages/workflows/workflow.component.html

@ -32,6 +32,15 @@
<div class="table-items-row-details" *ngIf="isEditing">
<div class="table-items-row-details-tabs clearfix">
<ul class="nav nav-tabs2">
<li class="nav-item">
<a class="nav-link" (click)="selectTab(0)" [class.active]="selectedTab === 0">Editing</a>
</li>
<li class="nav-item">
<a class="nav-link" (click)="selectTab(1)" [class.active]="selectedTab === 1">Visualize</a>
</li>
</ul>
<div class="float-right">
<button type="reset" class="btn btn-text-secondary2" (click)="toggleEditing()">Cancel</button>
<button type="submit" class="btn btn-primary ml-1" *ngIf="isEditable" (click)="save()">Save</button>
@ -39,57 +48,61 @@
</div>
<div class="table-items-row-details-tab">
<sqx-form-error [error]="error"></sqx-form-error>
<div class="form-group row">
<label class="col-form-label" for="{{workflow.id}}_name">Name</label>
<div class="col">
<input class="form-control" id="{{workflow.id}}_name"
[ngModelOptions]="onBlur"
[ngModel]="workflow.name"
(ngModelChange)="rename($event)" />
<sqx-form-hint>
Optional name for the workflow.
</sqx-form-hint>
<ng-container *ngIf="selectedTab === 0; else visualize">
<sqx-form-error [error]="error"></sqx-form-error>
<div class="form-group row">
<label class="col-form-label" for="{{workflow.id}}_name">Name</label>
<div class="col">
<input class="form-control" id="{{workflow.id}}_name"
[ngModelOptions]="onBlur"
[ngModel]="workflow.name"
(ngModelChange)="rename($event)" />
<sqx-form-hint>
Optional name for the workflow.
</sqx-form-hint>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-form-label" for="{{workflow.id}}_schemas">Schemas</label>
<div class="col">
<sqx-tag-editor placeholder=", to add schema"
[converter]="schemasSource.converter | async"
[ngModel]="workflow.schemaIds"
(ngModelChange)="changeSchemaIds($event)"
[suggestions]="(schemasSource.converter | async)?.suggestions">
</sqx-tag-editor>
<sqx-form-hint>
Restrict this workflow to specific schemas or keep it empty for all schemas.
</sqx-form-hint>
<div class="form-group row">
<label class="col-form-label" for="{{workflow.id}}_schemas">Schemas</label>
<div class="col">
<sqx-tag-editor placeholder=", to add schema"
[converter]="schemasSource.converter | async"
[ngModel]="workflow.schemaIds"
(ngModelChange)="changeSchemaIds($event)"
[suggestions]="(schemasSource.converter | async)?.suggestions">
</sqx-tag-editor>
<sqx-form-hint>
Restrict this workflow to specific schemas or keep it empty for all schemas.
</sqx-form-hint>
</div>
</div>
</div>
<sqx-workflow-step *ngFor="let step of workflow.steps; trackBy: trackByStep"
[workflow]="workflow"
[disabled]="!workflow.canUpdate"
[roles]="roles"
[step]="step"
(makeInitial)="setInitial(step)"
(rename)="renameStep(step, $event)"
(remove)="removeStep(step)"
(transitionAdd)="addTransiton(step, $event)"
(transitionRemove)="removeTransition(step, $event)"
(transitionUpdate)="updateTransition($event)"
(update)="updateStep(step, $event)">
</sqx-workflow-step>
<sqx-workflow-step *ngFor="let step of workflow.steps; trackBy: trackByStep" [step]="step" [workflow]="workflow"
[disabled]="!workflow.canUpdate"
(makeInitial)="setInitial(step)"
(rename)="renameStep(step, $event)"
(remove)="removeStep(step)"
(transitionAdd)="addTransiton(step, $event)"
(transitionRemove)="removeTransition(step, $event)"
(transitionUpdate)="updateTransition($event)"
(update)="updateStep(step, $event)"
[roles]="roles">
</sqx-workflow-step>
<button class="btn btn-success" (click)="addStep()" *ngIf="workflow.canUpdate">
Add Step
</button>
</ng-container>
<button class="btn btn-success" (click)="addStep()" *ngIf="workflow.canUpdate">
Add Step
</button>
<ng-template #visualize>
<sqx-workflow-diagram [workflow]="workflow"></sqx-workflow-diagram>
</ng-template>
</div>
</div>
</div>

6
frontend/app/features/settings/pages/workflows/workflow.component.ts

@ -32,6 +32,8 @@ export class WorkflowComponent implements OnChanges {
public isEditing = false;
public isEditable = false;
public selectedTab = 0;
constructor(
private readonly workflowsState: WorkflowsState
) {
@ -111,6 +113,10 @@ export class WorkflowComponent implements OnChanges {
this.workflow = this.workflow.removeStep(step.name);
}
public selectTab(tab: number) {
this.selectedTab = tab;
}
public trackByStep(index: number, step: WorkflowStep) {
return step.name;
}

33
frontend/package-lock.json

@ -414,6 +414,14 @@
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==",
"dev": true
},
"@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
"integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
"requires": {
"@types/hammerjs": "^2.0.36"
}
},
"@ngtools/webpack": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.0.6.tgz",
@ -534,6 +542,11 @@
"@types/node": "*"
}
},
"@types/hammerjs": {
"version": "2.0.36",
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.36.tgz",
"integrity": "sha512-7TUK/k2/QGpEAv/BCwSHlYu3NXZhQ9ZwBYpzr9tjlPIL2C5BeGhH3DmVavRx3ZNyELX5TLC91JTz/cen6AAtIQ=="
},
"@types/jasmine": {
"version": "3.5.9",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.9.tgz",
@ -7366,6 +7379,11 @@
}
}
},
"keycharm": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.3.1.tgz",
"integrity": "sha512-zn47Ti4FJT9zdF+YBBLWJsfKF/fYQHkrYlBeB5Ez5e2PjW7SoIxr43yehAne2HruulIoid4NKZZxO0dHBygCtQ=="
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@ -13402,6 +13420,21 @@
"extsprintf": "^1.2.0"
}
},
"vis-data": {
"version": "6.6.1",
"resolved": "https://registry.npmjs.org/vis-data/-/vis-data-6.6.1.tgz",
"integrity": "sha512-xmujDB2Dzf8T04rGFJ9OP4OA6zRVrz8R9hb0CVKryBrZRCljCga9JjSfgctA8S7wdZu7otDtUIwX4ZOgfV/57w=="
},
"vis-network": {
"version": "7.10.0",
"resolved": "https://registry.npmjs.org/vis-network/-/vis-network-7.10.0.tgz",
"integrity": "sha512-SYQ3y+cGqcFpPfaQbpGBXsaQjjbQq5xjt5dVztCD6x5ETQHlAYaFiYiWnVo0qoVI9lspfwoCfp4wOhW+rvId6Q=="
},
"vis-util": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/vis-util/-/vis-util-4.3.2.tgz",
"integrity": "sha512-FIS75hhrzbX1qJwFVwVVm1q2/TEktJWjgWsV0T3E9AYC4PWyQCBKk2LgsSLi+O8NBi7gTe9D4K75MqdPTHrRnA=="
},
"vm-browserify": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",

5
frontend/package.json

@ -26,6 +26,7 @@
"@angular/platform-browser-dynamic": "9.0.6",
"@angular/platform-server": "9.0.6",
"@angular/router": "9.0.6",
"@egjs/hammerjs": "^2.0.17",
"ace-builds": "^1.4.11",
"angular-gridster2": "^9.2.0",
"angular-mentions": "1.1.4",
@ -39,6 +40,7 @@
"graphiql": "0.17.5",
"graphql": "14.6.0",
"image-focus": "1.1.0",
"keycharm": "^0.3.1",
"marked": "0.8.0",
"mersenne-twister": "1.1.0",
"mousetrap": "1.6.5",
@ -53,6 +55,9 @@
"slugify": "1.4.0",
"tinymce": "^5.2.0",
"tslib": "1.11.1",
"vis-data": "^6.6.1",
"vis-network": "^7.10.0",
"vis-util": "^4.3.2",
"zone.js": "0.10.3"
},
"devDependencies": {

Loading…
Cancel
Save