diff --git a/src/Squidex.Domain.Apps.Core.Model/Apps/AppClient.cs b/src/Squidex.Domain.Apps.Core.Model/Apps/AppClient.cs index fd670011f..518ecd646 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Apps/AppClient.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Apps/AppClient.cs @@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Core.Apps { Guard.NotNullOrEmpty(secret, nameof(secret)); Guard.NotNullOrEmpty(role, nameof(role)); - + Role = role; Secret = secret; diff --git a/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs b/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs index 15ed0a51c..864961903 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Apps/AppPattern.cs @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Core.Apps : base(name) { Guard.NotNullOrEmpty(pattern, nameof(pattern)); - + Pattern = pattern; Message = message; diff --git a/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesConverter.cs b/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesConverter.cs index 51b23d192..2a7be22e2 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesConverter.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesConverter.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Newtonsoft.Json; -using Squidex.Infrastructure.Json.Newtonsoft; -using Squidex.Infrastructure.Security; using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; +using Squidex.Infrastructure.Json.Newtonsoft; +using Squidex.Infrastructure.Security; namespace Squidex.Domain.Apps.Core.Apps.Json { diff --git a/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs b/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs index 0e2770682..22f6f1b73 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; -using Squidex.Infrastructure.Security; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Security; using P = Squidex.Shared.Permissions; namespace Squidex.Domain.Apps.Core.Apps @@ -71,7 +71,8 @@ namespace Squidex.Domain.Apps.Core.Apps return new Role(Editor, P.ForApp(P.AppAssets, app), P.ForApp(P.AppCommon, app), - P.ForApp(P.AppContents, app)); + P.ForApp(P.AppContents, app), + P.ForApp(P.AppWorkflowsRead, app)); } public static Role CreateReader(string app) @@ -90,6 +91,7 @@ namespace Squidex.Domain.Apps.Core.Apps P.ForApp(P.AppCommon, app), P.ForApp(P.AppContents, app), P.ForApp(P.AppPatterns, app), + P.ForApp(P.AppWorkflows, app), P.ForApp(P.AppRules, app), P.ForApp(P.AppSchemas, app)); } diff --git a/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs b/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs index 58e7c5bfa..4e3e1d066 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; -using Squidex.Infrastructure.Collections; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Core.Apps { diff --git a/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs b/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs index a9b2bb7cb..61a90f23c 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Comments/Comment.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using NodaTime; using Squidex.Infrastructure; -using System; namespace Squidex.Domain.Apps.Core.Comments { diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/Json/StatusConverter.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/Json/StatusConverter.cs index a56722c55..286b83d12 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Contents/Json/StatusConverter.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/Json/StatusConverter.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Newtonsoft.Json; -using Squidex.Infrastructure.Json.Newtonsoft; using System; using System.Collections.Generic; +using Newtonsoft.Json; +using Squidex.Infrastructure.Json.Newtonsoft; namespace Squidex.Domain.Apps.Core.Contents.Json { diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/Json/WorkflowConverter.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/Json/WorkflowConverter.cs new file mode 100644 index 000000000..84e8092ee --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/Json/WorkflowConverter.cs @@ -0,0 +1,37 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Squidex.Infrastructure.Json.Newtonsoft; + +namespace Squidex.Domain.Apps.Core.Contents.Json +{ + public sealed class WorkflowConverter : JsonClassConverter + { + protected override void WriteValue(JsonWriter writer, Workflows value, JsonSerializer serializer) + { + var json = new Dictionary(value.Count); + + foreach (var workflow in value) + { + json.Add(workflow.Key, workflow.Value); + } + + serializer.Serialize(writer, json); + } + + protected override Workflows ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer) + { + var json = serializer.Deserialize>(reader); + + return new Workflows(json.ToArray()); + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs index cc204e759..32026fc44 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs @@ -6,9 +6,11 @@ // ========================================================================== using System; +using System.ComponentModel; namespace Squidex.Domain.Apps.Core.Contents { + [TypeConverter(typeof(StatusConverter))] public struct Status : IEquatable { public static readonly Status Archived = new Status("Archived"); diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/StatusConverter.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/StatusConverter.cs new file mode 100644 index 000000000..a7ba559c7 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/StatusConverter.cs @@ -0,0 +1,36 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.ComponentModel; +using System.Globalization; + +namespace Squidex.Domain.Apps.Core.Contents +{ + public sealed class StatusConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return destinationType == typeof(string); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + return new Status(value?.ToString()); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + return value.ToString(); + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/Workflow.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/Workflow.cs new file mode 100644 index 000000000..859e546ef --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/Workflow.cs @@ -0,0 +1,88 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; + +namespace Squidex.Domain.Apps.Core.Contents +{ + public sealed class Workflow + { + private static readonly IReadOnlyDictionary EmptySteps = new Dictionary(); + + public static readonly Workflow Default = new Workflow( + new Dictionary + { + [Status.Archived] = + new WorkflowStep( + new Dictionary + { + [Status.Draft] = new WorkflowTransition() + }, + StatusColors.Archived, true), + [Status.Draft] = + new WorkflowStep( + new Dictionary + { + [Status.Archived] = new WorkflowTransition(), + [Status.Published] = new WorkflowTransition() + }, + StatusColors.Draft), + [Status.Published] = + new WorkflowStep( + new Dictionary + { + [Status.Archived] = new WorkflowTransition(), + [Status.Draft] = new WorkflowTransition() + }, + StatusColors.Published) + }, Status.Draft); + + public IReadOnlyDictionary Steps { get; } + + public Status Initial { get; } + + public Workflow(IReadOnlyDictionary steps, Status initial) + { + Steps = steps ?? EmptySteps; + + Initial = initial; + } + + public IEnumerable<(Status Status, WorkflowStep Step, WorkflowTransition Transition)> GetTransitions(Status status) + { + if (TryGetStep(status, out var step)) + { + foreach (var transition in step.Transitions) + { + yield return (transition.Key, Steps[transition.Key], transition.Value); + } + } + } + + public bool TryGetTransition(Status from, Status to, out WorkflowTransition transition) + { + if (TryGetStep(from, out var step) && step.Transitions.TryGetValue(to, out transition)) + { + return true; + } + + transition = null; + + return false; + } + + public bool TryGetStep(Status status, out WorkflowStep step) + { + return Steps.TryGetValue(status, out step); + } + + public (Status Key, WorkflowStep) GetInitialStep() + { + return (Initial, Steps[Initial]); + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/WorkflowStep.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/WorkflowStep.cs new file mode 100644 index 000000000..04eb595c5 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/WorkflowStep.cs @@ -0,0 +1,31 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; + +namespace Squidex.Domain.Apps.Core.Contents +{ + public sealed class WorkflowStep + { + private static readonly IReadOnlyDictionary EmptyTransitions = new Dictionary(); + + public IReadOnlyDictionary Transitions { get; } + + public string Color { get; } + + public bool NoUpdate { get; } + + public WorkflowStep(IReadOnlyDictionary transitions = null, string color = null, bool noUpdate = false) + { + Transitions = transitions ?? EmptyTransitions; + + Color = color; + + NoUpdate = noUpdate; + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/WorkflowTransition.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/WorkflowTransition.cs new file mode 100644 index 000000000..5beed9a62 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/WorkflowTransition.cs @@ -0,0 +1,23 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Contents +{ + public sealed class WorkflowTransition + { + public string Expression { get; } + + public string Role { get; } + + public WorkflowTransition(string expression = null, string role = null) + { + Expression = expression; + + Role = role; + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs new file mode 100644 index 000000000..d027b8d32 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs @@ -0,0 +1,43 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; + +namespace Squidex.Domain.Apps.Core.Contents +{ + public sealed class Workflows : ArrayDictionary + { + public static readonly Workflows Empty = new Workflows(); + + private Workflows() + { + } + + public Workflows(KeyValuePair[] items) + : base(items) + { + } + + [Pure] + public Workflows Set(Workflow workflow) + { + Guard.NotNull(workflow, nameof(workflow)); + + return new Workflows(With(Guid.Empty, workflow)); + } + + public Workflow GetFirst() + { + return Values.FirstOrDefault() ?? Workflow.Default; + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerV2.cs b/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerV2.cs index ed1d9b033..d9c958390 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerV2.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Rules/Triggers/ContentChangedTriggerV2.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; using System.Collections.ObjectModel; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Rules.Triggers { diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs index 99d62bd4e..77cf55f72 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas { diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs index f07114303..4450ef2d1 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs @@ -16,7 +16,7 @@ namespace Squidex.Domain.Apps.Core.Schemas public sealed class FieldCollection : Cloneable> where T : IField { public static readonly FieldCollection Empty = new FieldCollection(); - + private static readonly Dictionary EmptyById = new Dictionary(); private static readonly Dictionary EmptyByString = new Dictionary(); diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs index 88a11c699..76ba5da7d 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; using System.Collections.Generic; using System.Linq; +using Squidex.Infrastructure; using NamedIdStatic = Squidex.Infrastructure.NamedId; namespace Squidex.Domain.Apps.Core.Schemas diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs index 78e3d3f81..729e6ab0c 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonFieldModel.cs @@ -5,9 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using Newtonsoft.Json; using Squidex.Infrastructure; -using System; using P = Squidex.Domain.Apps.Core.Partitioning; namespace Squidex.Domain.Apps.Core.Schemas.Json diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs index b7dfb78d4..5dc24c564 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/JsonFieldProperties.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== - namespace Squidex.Domain.Apps.Core.Schemas { public sealed class JsonFieldProperties : FieldProperties diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs index b1d672216..23989053a 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; using System; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Schemas { diff --git a/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj b/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj index 7a88572ce..f5b9cd862 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj +++ b/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj @@ -14,6 +14,8 @@ runtime; build; native; contentfiles; analyzers + + diff --git a/src/Squidex.Domain.Apps.Entities/AppProvider.cs b/src/Squidex.Domain.Apps.Entities/AppProvider.cs index a227d68bf..82507f4d9 100644 --- a/src/Squidex.Domain.Apps.Entities/AppProvider.cs +++ b/src/Squidex.Domain.Apps.Entities/AppProvider.cs @@ -65,6 +65,17 @@ namespace Squidex.Domain.Apps.Entities }); } + public Task GetAppAsync(Guid appId) + { + return localCache.GetOrCreateAsync($"GetAppAsync({appId})", async () => + { + using (Profiler.TraceMethod()) + { + return await GetAppByIdAsync(appId); + } + }); + } + public Task GetAppAsync(string appName) { return localCache.GetOrCreateAsync($"GetAppAsync({appName})", async () => @@ -78,14 +89,7 @@ namespace Squidex.Domain.Apps.Entities return null; } - var app = await grainFactory.GetGrain(appId).GetStateAsync(); - - if (!IsExisting(app)) - { - return null; - } - - return app.Value; + return await GetAppByIdAsync(appId); } }); } @@ -184,6 +188,18 @@ namespace Squidex.Domain.Apps.Entities }); } + private async Task GetAppByIdAsync(Guid appId) + { + var app = await grainFactory.GetGrain(appId).GetStateAsync(); + + if (!IsExisting(app)) + { + return null; + } + + return app.Value; + } + private async Task> GetAppIdsByUserAsync(string userId) { using (Profiler.TraceMethod()) diff --git a/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs b/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs index eceb7bfa5..e17c17290 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs @@ -119,6 +119,16 @@ namespace Squidex.Domain.Apps.Entities.Apps return Snapshot; }); + case ConfigureWorkflow configureWorkflow: + return UpdateReturn(configureWorkflow, c => + { + GuardAppWorkflows.CanConfigure(c); + + ConfigureWorkflow(c); + + return Snapshot; + }); + case AddLanguage addLanguage: return UpdateReturn(addLanguage, c => { @@ -319,6 +329,11 @@ namespace Squidex.Domain.Apps.Entities.Apps RaiseEvent(SimpleMapper.Map(command, new AppClientRevoked())); } + public void ConfigureWorkflow(ConfigureWorkflow command) + { + RaiseEvent(SimpleMapper.Map(command, new AppWorkflowConfigured())); + } + public void AddLanguage(AddLanguage command) { RaiseEvent(SimpleMapper.Map(command, new AppLanguageAdded())); diff --git a/src/Squidex.Web/IAppFeature.cs b/src/Squidex.Domain.Apps.Entities/Apps/Commands/ConfigureWorkflow.cs similarity index 57% rename from src/Squidex.Web/IAppFeature.cs rename to src/Squidex.Domain.Apps.Entities/Apps/Commands/ConfigureWorkflow.cs index a798da598..efa2b503b 100644 --- a/src/Squidex.Web/IAppFeature.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Commands/ConfigureWorkflow.cs @@ -1,16 +1,16 @@ // ========================================================================== // Squidex Headless CMS // ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) +// Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Domain.Apps.Core.Contents; -namespace Squidex.Web +namespace Squidex.Domain.Apps.Entities.Apps.Commands { - public interface IAppFeature + public sealed class ConfigureWorkflow : AppCommand { - IAppEntity App { get; } + public Workflow Workflow { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppWorkflows.cs b/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppWorkflows.cs new file mode 100644 index 000000000..1e675ac8e --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppWorkflows.cs @@ -0,0 +1,76 @@ +// ========================================================================== +// 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.Entities.Apps.Commands; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Apps.Guards +{ + public static class GuardAppWorkflows + { + public static void CanConfigure(ConfigureWorkflow command) + { + Guard.NotNull(command, nameof(command)); + + Validate.It(() => "Cannot configure workflow.", e => + { + if (command.Workflow == null) + { + e(Not.Defined("Workflow"), nameof(command.Workflow)); + return; + } + + var workflow = command.Workflow; + + if (!workflow.Steps.ContainsKey(workflow.Initial)) + { + e(Not.Defined("Initial step"), $"{nameof(command.Workflow)}.{nameof(workflow.Initial)}"); + } + + if (workflow.Initial == Status.Published) + { + e("Initial step cannot be published step.", $"{nameof(command.Workflow)}.{nameof(workflow.Initial)}"); + } + + var stepsPrefix = $"{nameof(command.Workflow)}.{nameof(workflow.Steps)}"; + + if (!workflow.Steps.ContainsKey(Status.Published)) + { + e("Workflow must have a published step.", stepsPrefix); + } + + foreach (var step in workflow.Steps) + { + var stepPrefix = $"{stepsPrefix}.{step.Key}"; + + if (step.Value == null) + { + e(Not.Defined("Step"), stepPrefix); + } + else + { + foreach (var transition in step.Value.Transitions) + { + var transitionPrefix = $"{stepPrefix}.{nameof(step.Value.Transitions)}.{transition.Key}"; + + if (!workflow.Steps.ContainsKey(transition.Key)) + { + e("Transition has an invalid target.", transitionPrefix); + } + + if (transition.Value == null) + { + e(Not.Defined("Transition"), transitionPrefix); + } + } + } + } + }); + } + } +} diff --git a/src/Squidex.Domain.Apps.Entities/Apps/IAppEntity.cs b/src/Squidex.Domain.Apps.Entities/Apps/IAppEntity.cs index bf81d2612..a41e3368f 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/IAppEntity.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/IAppEntity.cs @@ -6,6 +6,7 @@ // ========================================================================== using Squidex.Domain.Apps.Core.Apps; +using Squidex.Domain.Apps.Core.Contents; namespace Squidex.Domain.Apps.Entities.Apps { @@ -29,6 +30,8 @@ namespace Squidex.Domain.Apps.Entities.Apps LanguagesConfig LanguagesConfig { get; } + Workflows Workflows { get; } + bool IsArchived { get; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs b/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs index 4f31dbdc0..ac71df0bc 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs @@ -7,6 +7,7 @@ using System.Runtime.Serialization; using Squidex.Domain.Apps.Core.Apps; +using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Apps; using Squidex.Infrastructure.Dispatching; @@ -42,6 +43,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.State [DataMember] public LanguagesConfig LanguagesConfig { get; set; } = LanguagesConfig.English; + [DataMember] + public Workflows Workflows { get; set; } = Workflows.Empty; + [DataMember] public bool IsArchived { get; set; } @@ -92,6 +96,11 @@ namespace Squidex.Domain.Apps.Entities.Apps.State Clients = Clients.Revoke(@event.Id); } + protected void On(AppWorkflowConfigured @event) + { + Workflows = Workflows.Set(@event.Workflow); + } + protected void On(AppPatternAdded @event) { Patterns = Patterns.Add(@event.PatternId, @event.Name, @event.Pattern, @event.Message); diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs index 29d6b28e9..0dc427439 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs @@ -70,7 +70,7 @@ namespace Squidex.Domain.Apps.Entities.Assets return await assetEnricher.EnrichAsync(assets); } - public async Task> QueryAsync(QueryContext context, Q query) + public async Task> QueryAsync(Context context, Q query) { Guard.NotNull(context, nameof(context)); Guard.NotNull(query, nameof(query)); @@ -91,14 +91,14 @@ namespace Squidex.Domain.Apps.Entities.Assets return ResultList.Create(assets.Total, enriched); } - private async Task> QueryByQueryAsync(QueryContext context, Q query) + private async Task> QueryByQueryAsync(Context context, Q query) { var parsedQuery = ParseQuery(context, query.ODataQuery); return await assetRepository.QueryAsync(context.App.Id, parsedQuery); } - private async Task> QueryByIdsAsync(QueryContext context, Q query) + private async Task> QueryByIdsAsync(Context context, Q query) { var assets = await assetRepository.QueryAsync(context.App.Id, new HashSet(query.Ids)); @@ -110,7 +110,7 @@ namespace Squidex.Domain.Apps.Entities.Assets return assets.SortSet(x => x.Id, ids); } - private Query ParseQuery(QueryContext context, string query) + private Query ParseQuery(Context context, string query) { try { diff --git a/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs b/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs index a186e376c..bec9309a6 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs @@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Assets Task> QueryByHashAsync(Guid appId, string hash); - Task> QueryAsync(QueryContext contex, Q query); + Task> QueryAsync(Context contex, Q query); Task FindAssetAsync(Guid id); } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs index d72e3eee1..63bc61a96 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs @@ -30,12 +30,17 @@ namespace Squidex.Domain.Apps.Entities.Contents { await base.HandleAsync(context, next); - if (context.PlainResult is IContentEntity content && !(context.PlainResult is IEnrichedContentEntity)) + if (context.Command is SquidexCommand command && context.PlainResult is IContentEntity content && NotEnriched(context)) { - var enriched = await contentEnricher.EnrichAsync(content); + var enriched = await contentEnricher.EnrichAsync(content, command.User); context.Complete(enriched); } } + + private static bool NotEnriched(CommandContext context) + { + return !(context.PlainResult is IEnrichedContentEntity); + } } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs index e87aada08..32d93b04d 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; using Squidex.Infrastructure; @@ -20,24 +21,30 @@ namespace Squidex.Domain.Apps.Entities.Contents { private const string DefaultColor = StatusColors.Draft; private readonly IContentWorkflow contentWorkflow; + private readonly IContextProvider contextProvider; - public ContentEnricher(IContentWorkflow contentWorkflow) + public ContentEnricher(IContentWorkflow contentWorkflow, IContextProvider contextProvider) { + Guard.NotNull(contentWorkflow, nameof(contentWorkflow)); + Guard.NotNull(contextProvider, nameof(contextProvider)); + this.contentWorkflow = contentWorkflow; + this.contextProvider = contextProvider; } - public async Task EnrichAsync(IContentEntity content) + public async Task EnrichAsync(IContentEntity content, ClaimsPrincipal user) { Guard.NotNull(content, nameof(content)); - var enriched = await EnrichAsync(Enumerable.Repeat(content, 1)); + var enriched = await EnrichAsync(Enumerable.Repeat(content, 1), user); return enriched[0]; } - public async Task> EnrichAsync(IEnumerable contents) + public async Task> EnrichAsync(IEnumerable contents, ClaimsPrincipal user) { Guard.NotNull(contents, nameof(contents)); + Guard.NotNull(user, nameof(user)); using (Profiler.TraceMethod()) { @@ -50,8 +57,12 @@ namespace Squidex.Domain.Apps.Entities.Contents var result = SimpleMapper.Map(content, new ContentEntity()); await ResolveColorAsync(content, result, cache); - await ResolveNextsAsync(content, result); - await ResolveCanUpdateAsync(content, result); + + if (ShouldEnrichWithStatuses()) + { + await ResolveNextsAsync(content, result, user); + await ResolveCanUpdateAsync(content, result); + } results.Add(result); } @@ -60,33 +71,38 @@ namespace Squidex.Domain.Apps.Entities.Contents } } + private bool ShouldEnrichWithStatuses() + { + return contextProvider.Context.IsFrontendClient || contextProvider.Context.IsResolveFlow(); + } + private async Task ResolveCanUpdateAsync(IContentEntity content, ContentEntity result) { result.CanUpdate = await contentWorkflow.CanUpdateAsync(content); } - private async Task ResolveNextsAsync(IContentEntity content, ContentEntity result) + private async Task ResolveNextsAsync(IContentEntity content, ContentEntity result, ClaimsPrincipal user) { - result.Nexts = await contentWorkflow.GetNextsAsync(content); + result.Nexts = await contentWorkflow.GetNextsAsync(content, user); } private async Task ResolveColorAsync(IContentEntity content, ContentEntity result, Dictionary<(Guid, Status), StatusInfo> cache) { - result.StatusColor = await GetColorAsync(content.SchemaId, content.Status, cache); + result.StatusColor = await GetColorAsync(content, cache); } - private async Task GetColorAsync(NamedId schemaId, Status status, Dictionary<(Guid, Status), StatusInfo> cache) + private async Task GetColorAsync(IContentEntity content, Dictionary<(Guid, Status), StatusInfo> cache) { - if (!cache.TryGetValue((schemaId.Id, status), out var info)) + if (!cache.TryGetValue((content.SchemaId.Id, content.Status), out var info)) { - info = await contentWorkflow.GetInfoAsync(status); + info = await contentWorkflow.GetInfoAsync(content); if (info == null) { - info = new StatusInfo(status, DefaultColor); + info = new StatusInfo(content.Status, DefaultColor); } - cache[(schemaId.Id, status)] = info; + cache[(content.SchemaId.Id, content.Status)] = info; } return info.Color; diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs index 88d8907be..306b49309 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs @@ -78,13 +78,13 @@ namespace Squidex.Domain.Apps.Entities.Contents this.scriptEngine = scriptEngine; } - public async Task FindContentAsync(QueryContext context, string schemaIdOrName, Guid id, long version = -1) + public async Task FindContentAsync(Context context, string schemaIdOrName, Guid id, long version = -1) { Guard.NotNull(context, nameof(context)); var schema = await GetSchemaOrThrowAsync(context, schemaIdOrName); - CheckPermission(context.User, schema); + CheckPermission(context, schema); using (Profiler.TraceMethod()) { @@ -108,13 +108,13 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - public async Task> QueryAsync(QueryContext context, string schemaIdOrName, Q query) + public async Task> QueryAsync(Context context, string schemaIdOrName, Q query) { Guard.NotNull(context, nameof(context)); var schema = await GetSchemaOrThrowAsync(context, schemaIdOrName); - CheckPermission(context.User, schema); + CheckPermission(context, schema); using (Profiler.TraceMethod()) { @@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - public async Task> QueryAsync(QueryContext context, IReadOnlyList ids) + public async Task> QueryAsync(Context context, IReadOnlyList ids) { Guard.NotNull(context, nameof(context)); @@ -148,13 +148,11 @@ namespace Squidex.Domain.Apps.Entities.Contents var contents = await QueryCoreAsync(context, ids); - var permissions = context.User.Permissions(); - foreach (var group in contents.GroupBy(x => x.Schema.Id)) { var schema = group.First().Schema; - if (HasPermission(permissions, schema)) + if (HasPermission(context, schema)) { var enriched = await TransformCoreAsync(context, schema, group.Select(x => x.Content)); @@ -166,21 +164,21 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - private async Task> TransformAsync(QueryContext context, ISchemaEntity schema, IResultList contents) + private async Task> TransformAsync(Context context, ISchemaEntity schema, IResultList contents) { var transformed = await TransformCoreAsync(context, schema, contents); return ResultList.Create(contents.Total, transformed); } - private async Task TransformAsync(QueryContext context, ISchemaEntity schema, IContentEntity content) + private async Task TransformAsync(Context context, ISchemaEntity schema, IContentEntity content) { var transformed = await TransformCoreAsync(context, schema, Enumerable.Repeat(content, 1)); return transformed[0]; } - private async Task> TransformCoreAsync(QueryContext context, ISchemaEntity schema, IEnumerable contents) + private async Task> TransformCoreAsync(Context context, ISchemaEntity schema, IEnumerable contents) { using (Profiler.TraceMethod()) { @@ -191,7 +189,7 @@ namespace Squidex.Domain.Apps.Entities.Contents var scriptText = schema.SchemaDef.Scripts.Query; var scripting = !string.IsNullOrWhiteSpace(scriptText); - var enriched = await contentEnricher.EnrichAsync(contents); + var enriched = await contentEnricher.EnrichAsync(contents, context.User); foreach (var content in enriched) { @@ -209,7 +207,7 @@ namespace Squidex.Domain.Apps.Entities.Contents result.Data = result.Data.ConvertName2Name(schema.SchemaDef, converters); } - if (result.DataDraft != null && (context.ApiStatus == StatusForApi.All || context.IsFrontendClient)) + if (result.DataDraft != null && (context.IsUnpublished() || context.IsFrontendClient)) { result.DataDraft = result.DataDraft.ConvertName2Name(schema.SchemaDef, converters); } @@ -225,7 +223,7 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - private IEnumerable GenerateConverters(QueryContext context) + private IEnumerable GenerateConverters(Context context) { if (!context.IsFrontendClient) { @@ -243,19 +241,23 @@ namespace Squidex.Domain.Apps.Entities.Contents { yield return FieldConverters.ResolveFallbackLanguages(context.App.LanguagesConfig); - if (context.Languages?.Any() == true) + var languages = context.Languages(); + + if (languages.Any()) { - yield return FieldConverters.FilterLanguages(context.App.LanguagesConfig, context.Languages); + yield return FieldConverters.FilterLanguages(context.App.LanguagesConfig, languages); } - if (context.AssetUrlsToResolve?.Any() == true) + var assetUrls = context.AssetUrls(); + + if (assetUrls.Any() == true) { - yield return FieldConverters.ResolveAssetUrls(context.AssetUrlsToResolve, assetUrlGenerator); + yield return FieldConverters.ResolveAssetUrls(assetUrls.ToList(), assetUrlGenerator); } } } - private Query ParseQuery(QueryContext context, string query, ISchemaEntity schema) + private Query ParseQuery(Context context, string query, ISchemaEntity schema) { using (Profiler.TraceMethod()) { @@ -292,7 +294,7 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - public async Task GetSchemaOrThrowAsync(QueryContext context, string schemaIdOrName) + public async Task GetSchemaOrThrowAsync(Context context, string schemaIdOrName) { ISchemaEntity schema = null; @@ -314,29 +316,27 @@ namespace Squidex.Domain.Apps.Entities.Contents return schema; } - private static void CheckPermission(ClaimsPrincipal user, params ISchemaEntity[] schemas) + private static void CheckPermission(Context context, params ISchemaEntity[] schemas) { - var permissions = user.Permissions(); - foreach (var schema in schemas) { - if (!HasPermission(permissions, schema)) + if (!HasPermission(context, schema)) { throw new DomainForbiddenException("You do not have permission for this schema."); } } } - private static bool HasPermission(PermissionSet permissions, ISchemaEntity schema) + private static bool HasPermission(Context context, ISchemaEntity schema) { var permission = Permissions.ForApp(Permissions.AppContentsRead, schema.AppId.Name, schema.SchemaDef.Name); - return permissions.Allows(permission); + return context.Permissions.Allows(permission); } - private static Status[] GetStatus(QueryContext context) + private static Status[] GetStatus(Context context) { - if (context.IsFrontendClient || context.ApiStatus == StatusForApi.All) + if (context.IsFrontendClient || context.IsUnpublished()) { return null; } @@ -346,36 +346,36 @@ namespace Squidex.Domain.Apps.Entities.Contents } } - private async Task> QueryByQueryAsync(QueryContext context, Q query, ISchemaEntity schema) + private async Task> QueryByQueryAsync(Context context, Q query, ISchemaEntity schema) { var parsedQuery = ParseQuery(context, query.ODataQuery, schema); return await QueryCoreAsync(context, schema, parsedQuery); } - private async Task> QueryByIdsAsync(QueryContext context, Q query, ISchemaEntity schema) + private async Task> QueryByIdsAsync(Context context, Q query, ISchemaEntity schema) { var contents = await QueryCoreAsync(context, schema, query.Ids.ToHashSet()); return contents.SortSet(x => x.Id, query.Ids); } - private Task> QueryCoreAsync(QueryContext context, IReadOnlyList ids) + private Task> QueryCoreAsync(Context context, IReadOnlyList ids) { return contentRepository.QueryAsync(context.App, GetStatus(context), new HashSet(ids), WithDraft(context)); } - private Task> QueryCoreAsync(QueryContext context, ISchemaEntity schema, Query query) + private Task> QueryCoreAsync(Context context, ISchemaEntity schema, Query query) { return contentRepository.QueryAsync(context.App, schema, GetStatus(context), context.IsFrontendClient, query, WithDraft(context)); } - private Task> QueryCoreAsync(QueryContext context, ISchemaEntity schema, HashSet ids) + private Task> QueryCoreAsync(Context context, ISchemaEntity schema, HashSet ids) { return contentRepository.QueryAsync(context.App, schema, GetStatus(context), ids, WithDraft(context)); } - private Task FindCoreAsync(QueryContext context, Guid id, ISchemaEntity schema) + private Task FindCoreAsync(Context context, Guid id, ISchemaEntity schema) { return contentRepository.FindContentAsync(context.App, schema, GetStatus(context), id, WithDraft(context)); } @@ -385,9 +385,9 @@ namespace Squidex.Domain.Apps.Entities.Contents return contentVersionLoader.LoadAsync(id, version); } - private static bool WithDraft(QueryContext context) + private static bool WithDraft(Context context) { - return context.ApiStatus == StatusForApi.All || context.IsFrontendClient; + return context.IsUnpublished() || context.IsFrontendClient; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs new file mode 100644 index 000000000..78f208424 --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs @@ -0,0 +1,139 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Linq; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Contents +{ + public static class ContextExtensions + { + private const string HeaderUnpublished = "X-Unpublished"; + private const string HeaderFlatten = "X-Flatten"; + private const string HeaderLanguages = "X-Languages"; + private const string HeaderResolveFlow = "X-ResolveFlow"; + private const string HeaderResolveAssetUrls = "X-Resolve-Urls"; + private static readonly char[] Separators = { ',', ';' }; + + public static bool IsUnpublished(this Context context) + { + return context.Headers.ContainsKey(HeaderUnpublished); + } + + public static Context WithUnpublished(this Context context, bool value = true) + { + if (value) + { + context.Headers[HeaderUnpublished] = "1"; + } + else + { + context.Headers.Remove(HeaderUnpublished); + } + + return context; + } + + public static bool IsFlatten(this Context context) + { + return context.Headers.ContainsKey(HeaderFlatten); + } + + public static Context WithFlatten(this Context context, bool value = true) + { + if (value) + { + context.Headers[HeaderFlatten] = "1"; + } + else + { + context.Headers.Remove(HeaderFlatten); + } + + return context; + } + + public static bool IsResolveFlow(this Context context) + { + return context.Headers.ContainsKey(HeaderResolveFlow); + } + + public static Context WithResolveFlow(this Context context, bool value = true) + { + if (value) + { + context.Headers[HeaderResolveFlow] = "1"; + } + else + { + context.Headers.Remove(HeaderResolveFlow); + } + + return context; + } + + public static IEnumerable AssetUrls(this Context context) + { + if (context.Headers.TryGetValue(HeaderResolveAssetUrls, out var value)) + { + return value.Split(Separators, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToHashSet(); + } + + return Enumerable.Empty(); + } + + public static Context WithAssetUrlsToResolve(this Context context, IEnumerable fieldNames) + { + if (fieldNames?.Any() == true) + { + context.Headers[HeaderResolveAssetUrls] = string.Join(",", fieldNames); + } + else + { + context.Headers.Remove(HeaderResolveAssetUrls); + } + + return context; + } + + public static IEnumerable Languages(this Context context) + { + if (context.Headers.TryGetValue(HeaderResolveAssetUrls, out var value)) + { + var languages = new HashSet(); + + foreach (var iso2Code in value.Split(Separators, StringSplitOptions.RemoveEmptyEntries)) + { + if (Language.TryGetLanguage(iso2Code.Trim(), out var language)) + { + languages.Add(language); + } + } + + return languages; + } + + return Enumerable.Empty(); + } + + public static Context WithLanguages(this Context context, IEnumerable fieldNames) + { + if (fieldNames?.Any() == true) + { + context.Headers[HeaderLanguages] = string.Join(",", fieldNames); + } + else + { + context.Headers.Remove(HeaderLanguages); + } + + return context; + } + } +} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs b/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs index 6d0156868..0f0075906 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Schemas; @@ -53,7 +54,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return Task.FromResult(result); } - public Task CanMoveToAsync(IContentEntity content, Status next) + public Task CanMoveToAsync(IContentEntity content, Status next, ClaimsPrincipal user) { var result = Flow.TryGetValue(content.Status, out var step) && step.Transitions.Any(x => x.Status == next); @@ -67,14 +68,14 @@ namespace Squidex.Domain.Apps.Entities.Contents return Task.FromResult(result); } - public Task GetInfoAsync(Status status) + public Task GetInfoAsync(IContentEntity content) { - var result = Flow[status].Info; + var result = Flow[content.Status].Info; return Task.FromResult(result); } - public Task GetNextsAsync(IContentEntity content) + public Task GetNextsAsync(IContentEntity content, ClaimsPrincipal user) { var result = Flow.TryGetValue(content.Status, out var step) ? step.Transitions : Array.Empty(); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs b/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs new file mode 100644 index 000000000..6a302fcce --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs @@ -0,0 +1,129 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.Scripting; +using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Contents +{ + public sealed class DynamicContentWorkflow : IContentWorkflow + { + private readonly IScriptEngine scriptEngine; + private readonly IAppProvider appProvider; + + public DynamicContentWorkflow(IScriptEngine scriptEngine, IAppProvider appProvider) + { + Guard.NotNull(scriptEngine, nameof(scriptEngine)); + Guard.NotNull(appProvider, nameof(appProvider)); + + this.scriptEngine = scriptEngine; + + this.appProvider = appProvider; + } + + public async Task GetAllAsync(ISchemaEntity schema) + { + var workflow = await GetWorkflowAsync(schema.AppId.Id); + + return workflow.Steps.Select(x => new StatusInfo(x.Key, GetColor(x.Value))).ToArray(); + } + + public async Task CanMoveToAsync(IContentEntity content, Status next, ClaimsPrincipal user) + { + var workflow = await GetWorkflowAsync(content.AppId.Id); + + return workflow.TryGetTransition(content.Status, next, out var transition) && CanUse(transition, content, user); + } + + public async Task CanUpdateAsync(IContentEntity content) + { + var workflow = await GetWorkflowAsync(content.AppId.Id); + + if (workflow.TryGetStep(content.Status, out var step)) + { + return !step.NoUpdate; + } + + return true; + } + + public async Task GetInfoAsync(IContentEntity content) + { + var workflow = await GetWorkflowAsync(content.AppId.Id); + + if (workflow.TryGetStep(content.Status, out var step)) + { + return new StatusInfo(content.Status, GetColor(step)); + } + + return new StatusInfo(content.Status, StatusColors.Draft); + } + + public async Task GetInitialStatusAsync(ISchemaEntity schema) + { + var workflow = await GetWorkflowAsync(schema.AppId.Id); + + var (status, step) = workflow.GetInitialStep(); + + return new StatusInfo(status, GetColor(step)); + } + + public async Task GetNextsAsync(IContentEntity content, ClaimsPrincipal user) + { + var result = new List(); + + var workflow = await GetWorkflowAsync(content.AppId.Id); + + foreach (var (to, step, transition) in workflow.GetTransitions(content.Status)) + { + if (CanUse(transition, content, user)) + { + result.Add(new StatusInfo(to, GetColor(step))); + } + } + + return result.ToArray(); + } + + private bool CanUse(WorkflowTransition transition, IContentEntity content, ClaimsPrincipal user) + { + if (!string.IsNullOrWhiteSpace(transition.Role)) + { + if (!user.Claims.Any(x => x.Type == ClaimTypes.Role && x.Value == transition.Role)) + { + return false; + } + } + + if (!string.IsNullOrWhiteSpace(transition.Expression)) + { + return scriptEngine.Evaluate("data", content.DataDraft, transition.Expression); + } + + return true; + } + + private async Task GetWorkflowAsync(Guid appId) + { + var app = await appProvider.GetAppAsync(appId); + + return app?.Workflows.GetFirst(); + } + + private static string GetColor(WorkflowStep step) + { + return step.Color ?? StatusColors.Draft; + } + } +} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs index 1a01b229a..2d3d5e353 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs @@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL this.resolver = resolver; } - public async Task<(bool HasError, object Response)> QueryAsync(QueryContext context, params GraphQLQuery[] queries) + public async Task<(bool HasError, object Response)> QueryAsync(Context context, params GraphQLQuery[] queries) { Guard.NotNull(context, nameof(context)); Guard.NotNull(queries, nameof(queries)); @@ -43,7 +43,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return (result.Any(x => x.HasError), result.ToArray(x => x.Response)); } - public async Task<(bool HasError, object Response)> QueryAsync(QueryContext context, GraphQLQuery query) + public async Task<(bool HasError, object Response)> QueryAsync(Context context, GraphQLQuery query) { Guard.NotNull(context, nameof(context)); Guard.NotNull(query, nameof(query)); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs index db7e2859c..3841ac148 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs @@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL public ISemanticLog Log { get; } - public GraphQLExecutionContext(QueryContext context, IDependencyResolver resolver) + public GraphQLExecutionContext(Context context, IDependencyResolver resolver) : base(context, resolver.Resolve(), resolver.Resolve()) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLService.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLService.cs index 693f1fabf..65760a321 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphQLService.cs @@ -11,8 +11,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { public interface IGraphQLService { - Task<(bool HasError, object Response)> QueryAsync(QueryContext context, params GraphQLQuery[] queries); + Task<(bool HasError, object Response)> QueryAsync(Context context, params GraphQLQuery[] queries); - Task<(bool HasError, object Response)> QueryAsync(QueryContext context, GraphQLQuery query); + Task<(bool HasError, object Response)> QueryAsync(Context context, GraphQLQuery query); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs index 4395ffd11..70f78d9b5 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs @@ -76,7 +76,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards return Validate.It(() => "Cannot change status.", async e => { - if (!await contentWorkflow.CanMoveToAsync(content, command.Status)) + if (!await contentWorkflow.CanMoveToAsync(content, command.Status, command.User)) { if (content.Status == command.Status && content.Status == Status.Published) { diff --git a/src/Squidex.Domain.Apps.Entities/Contents/IContentEnricher.cs b/src/Squidex.Domain.Apps.Entities/Contents/IContentEnricher.cs index 1b7334134..e73e49c16 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/IContentEnricher.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/IContentEnricher.cs @@ -6,14 +6,15 @@ // ========================================================================== using System.Collections.Generic; +using System.Security.Claims; using System.Threading.Tasks; namespace Squidex.Domain.Apps.Entities.Contents { public interface IContentEnricher { - Task EnrichAsync(IContentEntity content); + Task EnrichAsync(IContentEntity content, ClaimsPrincipal user); - Task> EnrichAsync(IEnumerable contents); + Task> EnrichAsync(IEnumerable contents, ClaimsPrincipal user); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs b/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs index 11b64a42f..de784f55d 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs @@ -17,12 +17,12 @@ namespace Squidex.Domain.Apps.Entities.Contents { int DefaultPageSizeGraphQl { get; } - Task> QueryAsync(QueryContext context, IReadOnlyList ids); + Task> QueryAsync(Context context, IReadOnlyList ids); - Task> QueryAsync(QueryContext context, string schemaIdOrName, Q query); + Task> QueryAsync(Context context, string schemaIdOrName, Q query); - Task FindContentAsync(QueryContext context, string schemaIdOrName, Guid id, long version = EtagVersion.Any); + Task FindContentAsync(Context context, string schemaIdOrName, Guid id, long version = EtagVersion.Any); - Task GetSchemaOrThrowAsync(QueryContext context, string schemaIdOrName); + Task GetSchemaOrThrowAsync(Context context, string schemaIdOrName); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs b/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs index 8a2f0f571..fd2f9dd37 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Security.Claims; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Schemas; @@ -15,13 +16,13 @@ namespace Squidex.Domain.Apps.Entities.Contents { Task GetInitialStatusAsync(ISchemaEntity schema); - Task CanMoveToAsync(IContentEntity content, Status next); + Task CanMoveToAsync(IContentEntity content, Status next, ClaimsPrincipal user); Task CanUpdateAsync(IContentEntity content); - Task GetInfoAsync(Status status); + Task GetInfoAsync(IContentEntity content); - Task GetNextsAsync(IContentEntity content); + Task GetNextsAsync(IContentEntity content, ClaimsPrincipal user); Task GetAllAsync(ISchemaEntity schema); } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/QueryExecutionContext.cs b/src/Squidex.Domain.Apps.Entities/Contents/QueryExecutionContext.cs index a40896a94..2c50a0d1e 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/QueryExecutionContext.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/QueryExecutionContext.cs @@ -21,9 +21,9 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly ConcurrentDictionary cachedAssets = new ConcurrentDictionary(); private readonly IContentQueryService contentQuery; private readonly IAssetQueryService assetQuery; - private readonly QueryContext context; + private readonly Context context; - public QueryExecutionContext(QueryContext context, IAssetQueryService assetQuery, IContentQueryService contentQuery) + public QueryExecutionContext(Context context, IAssetQueryService assetQuery, IContentQueryService contentQuery) { Guard.NotNull(assetQuery, nameof(assetQuery)); Guard.NotNull(contentQuery, nameof(contentQuery)); diff --git a/src/Squidex.Domain.Apps.Entities/Context.cs b/src/Squidex.Domain.Apps.Entities/Context.cs new file mode 100644 index 000000000..2dea67ac7 --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Context.cs @@ -0,0 +1,45 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.Security.Claims; +using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Infrastructure.Security; +using Squidex.Shared.Identity; + +namespace Squidex.Domain.Apps.Entities +{ + public sealed class Context + { + public IDictionary Headers { get; } = new Dictionary(); + + public IAppEntity App { get; set; } + + public ClaimsPrincipal User { get; set; } + + public PermissionSet Permissions + { + get { return User?.Permissions() ?? PermissionSet.Empty; } + } + + public Context() + { + } + + public Context(ClaimsPrincipal user, IAppEntity app) + { + User = user; + + App = app; + } + + public bool IsFrontendClient + { + get { return User != null && User.IsInClient("squidex-frontend"); } + } + } +} diff --git a/src/Squidex.Domain.Apps.Entities/IAppProvider.cs b/src/Squidex.Domain.Apps.Entities/IAppProvider.cs index f40ca30ca..114ac3384 100644 --- a/src/Squidex.Domain.Apps.Entities/IAppProvider.cs +++ b/src/Squidex.Domain.Apps.Entities/IAppProvider.cs @@ -19,6 +19,8 @@ namespace Squidex.Domain.Apps.Entities { Task<(IAppEntity, ISchemaEntity)> GetAppWithSchemaAsync(Guid appId, Guid id); + Task GetAppAsync(Guid appId); + Task GetAppAsync(string appName); Task GetSchemaAsync(Guid appId, Guid id, bool allowDeleted = false); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/StatusForApi.cs b/src/Squidex.Domain.Apps.Entities/IContextProvider.cs similarity index 77% rename from src/Squidex.Domain.Apps.Entities/Contents/StatusForApi.cs rename to src/Squidex.Domain.Apps.Entities/IContextProvider.cs index e58b4c098..e6e2c67cf 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/StatusForApi.cs +++ b/src/Squidex.Domain.Apps.Entities/IContextProvider.cs @@ -5,11 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -namespace Squidex.Domain.Apps.Entities.Contents +namespace Squidex.Domain.Apps.Entities { - public enum StatusForApi + public interface IContextProvider { - PublishedOnly, - All, + Context Context { get; } } } diff --git a/src/Squidex.Domain.Apps.Entities/QueryContext.cs b/src/Squidex.Domain.Apps.Entities/QueryContext.cs deleted file mode 100644 index 094e56e3d..000000000 --- a/src/Squidex.Domain.Apps.Entities/QueryContext.cs +++ /dev/null @@ -1,116 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Security.Claims; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Contents; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Security; - -namespace Squidex.Domain.Apps.Entities -{ - public sealed class QueryContext : Cloneable - { - private static readonly char[] Separators = { ',', ';' }; - - public ClaimsPrincipal User { get; private set; } - - public IAppEntity App { get; private set; } - - public bool Flatten { get; set; } - - public StatusForApi ApiStatus { get; private set; } - - public IReadOnlyCollection AssetUrlsToResolve { get; private set; } - - public IReadOnlyCollection Languages { get; private set; } - - private QueryContext() - { - } - - public static QueryContext Create(IAppEntity app, ClaimsPrincipal user) - { - return new QueryContext { App = app, User = user }; - } - - public QueryContext WithFlatten(bool flatten) - { - return Clone(c => c.Flatten = flatten); - } - - public QueryContext WithUnpublished(bool unpublished) - { - return WithApiStatus(unpublished ? StatusForApi.All : StatusForApi.PublishedOnly); - } - - public QueryContext WithApiStatus(StatusForApi status) - { - return Clone(c => c.ApiStatus = status); - } - - public QueryContext WithAssetUrlsToResolve(IEnumerable fieldNames) - { - if (fieldNames != null) - { - return Clone(c => - { - var fields = new HashSet(StringComparer.OrdinalIgnoreCase); - - c.AssetUrlsToResolve?.Foreach(x => fields.Add(x)); - - foreach (var part in fieldNames) - { - foreach (var fieldName in part.Split(Separators, StringSplitOptions.RemoveEmptyEntries)) - { - fields.Add(fieldName.Trim()); - } - } - - c.AssetUrlsToResolve = fields; - }); - } - - return this; - } - - public QueryContext WithLanguages(IEnumerable languageCodes) - { - if (languageCodes != null) - { - return Clone(c => - { - var languages = new HashSet(); - - c.Languages?.Foreach(x => languages.Add(x)); - - foreach (var part in languageCodes) - { - foreach (var iso2Code in part.Split(Separators, StringSplitOptions.RemoveEmptyEntries)) - { - if (Language.TryGetLanguage(iso2Code.Trim(), out var language)) - { - languages.Add(language); - } - } - } - - c.Languages = languages; - }); - } - - return this; - } - - public bool IsFrontendClient - { - get { return User.IsInClient("squidex-frontend"); } - } - } -} diff --git a/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowConfigured.cs b/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowConfigured.cs new file mode 100644 index 000000000..65166ae97 --- /dev/null +++ b/src/Squidex.Domain.Apps.Events/Apps/AppWorkflowConfigured.cs @@ -0,0 +1,18 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure.EventSourcing; + +namespace Squidex.Domain.Apps.Events.Apps +{ + [EventType(nameof(AppWorkflowConfigured))] + public sealed class AppWorkflowConfigured : AppEvent + { + public Workflow Workflow { get; set; } + } +} diff --git a/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs b/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs index a42d030f5..fd7b6d533 100644 --- a/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs +++ b/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs @@ -36,6 +36,18 @@ namespace Squidex.Infrastructure.Json.Newtonsoft } } + protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) + { + if (objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)) + { + var implementationType = typeof(Dictionary<,>).MakeGenericType(objectType.GetGenericArguments()); + + return base.CreateDictionaryContract(implementationType); + } + + return base.CreateDictionaryContract(objectType); + } + protected override JsonConverter ResolveContractConverter(Type objectType) { var result = base.ResolveContractConverter(objectType); diff --git a/src/Squidex.Shared/Permissions.cs b/src/Squidex.Shared/Permissions.cs index 7118a0604..62329248e 100644 --- a/src/Squidex.Shared/Permissions.cs +++ b/src/Squidex.Shared/Permissions.cs @@ -81,6 +81,12 @@ namespace Squidex.Shared public const string AppPatternsUpdate = "squidex.apps.{app}.patterns.update"; public const string AppPatternsDelete = "squidex.apps.{app}.patterns.delete"; + public const string AppWorkflows = "squidex.apps.{app}.workflows"; + public const string AppWorkflowsRead = "squidex.apps.{app}.workflows.read"; + public const string AppWorkflowsCreate = "squidex.apps.{app}.workflows.create"; + public const string AppWorkflowsUpdate = "squidex.apps.{app}.workflows.update"; + public const string AppWorkflowsDelete = "squidex.apps.{app}.workflows.delete"; + public const string AppBackups = "squidex.apps.{app}.backups"; public const string AppBackupsRead = "squidex.apps.{app}.backups.read"; public const string AppBackupsCreate = "squidex.apps.{app}.backups.create"; diff --git a/src/Squidex.Web/ApiController.cs b/src/Squidex.Web/ApiController.cs index 2d4a8d517..a7ead50d9 100644 --- a/src/Squidex.Web/ApiController.cs +++ b/src/Squidex.Web/ApiController.cs @@ -8,6 +8,7 @@ using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -26,17 +27,22 @@ namespace Squidex.Web { get { - var appFeature = HttpContext.Features.Get(); + var app = HttpContext.Context().App; - if (appFeature == null) + if (app == null) { throw new InvalidOperationException("Not in a app context."); } - return appFeature.App; + return app; } } + protected Context Context + { + get { return HttpContext.Context(); } + } + protected Guid AppId { get { return App.Id; } diff --git a/src/Squidex.Web/ApiPermissionAttribute.cs b/src/Squidex.Web/ApiPermissionAttribute.cs index d515c76ce..e93e1fed2 100644 --- a/src/Squidex.Web/ApiPermissionAttribute.cs +++ b/src/Squidex.Web/ApiPermissionAttribute.cs @@ -36,23 +36,26 @@ namespace Squidex.Web { if (permissionIds.Length > 0) { - var set = context.HttpContext.User.Permissions(); + var permissions = context.HttpContext.Context().Permissions; var hasPermission = false; - foreach (var permissionId in permissionIds) + if (permissions != null) { - var id = permissionId; - - foreach (var routeParam in context.RouteData.Values) + foreach (var permissionId in permissionIds) { - id = id.Replace($"{{{routeParam.Key}}}", routeParam.Value?.ToString()); - } + var id = permissionId; - if (set.Allows(new Permission(id))) - { - hasPermission = true; - break; + foreach (var routeParam in context.RouteData.Values) + { + id = id.Replace($"{{{routeParam.Key}}}", routeParam.Value?.ToString()); + } + + if (permissions.Allows(new Permission(id))) + { + hasPermission = true; + break; + } } } diff --git a/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs b/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs index 0b7d872e5..394ee4aa7 100644 --- a/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs +++ b/src/Squidex.Web/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs @@ -7,7 +7,6 @@ using System; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure; @@ -17,20 +16,15 @@ namespace Squidex.Web.CommandMiddlewares { public sealed class EnrichWithAppIdCommandMiddleware : ICommandMiddleware { - private readonly IHttpContextAccessor httpContextAccessor; + private readonly IContextProvider contextProvider; - public EnrichWithAppIdCommandMiddleware(IHttpContextAccessor httpContextAccessor) + public EnrichWithAppIdCommandMiddleware(IContextProvider contextProvider) { - this.httpContextAccessor = httpContextAccessor; + this.contextProvider = contextProvider; } public Task HandleAsync(CommandContext context, Func next) { - if (httpContextAccessor.HttpContext == null) - { - return next(); - } - if (context.Command is IAppCommand appCommand && appCommand.AppId == null) { var appId = GetAppId(); @@ -50,14 +44,14 @@ namespace Squidex.Web.CommandMiddlewares private NamedId GetAppId() { - var appFeature = httpContextAccessor.HttpContext.Features.Get(); + var context = contextProvider.Context; - if (appFeature?.App == null) + if (context.App == null) { throw new InvalidOperationException("Cannot resolve app."); } - return appFeature.App.NamedId(); + return context.App.NamedId(); } } } \ No newline at end of file diff --git a/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs b/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs index a64798783..c837b5dd0 100644 --- a/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs +++ b/src/Squidex.Web/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs @@ -65,12 +65,7 @@ namespace Squidex.Web.CommandMiddlewares if (appId == null) { - var appFeature = actionContextAccessor.ActionContext.HttpContext.Features.Get(); - - if (appFeature?.App != null) - { - appId = appFeature.App.NamedId(); - } + appId = actionContextAccessor.ActionContext.HttpContext.Context().App?.NamedId(); } if (appId != null) diff --git a/src/Squidex.Web/ContextExtensions.cs b/src/Squidex.Web/ContextExtensions.cs new file mode 100644 index 000000000..7548e3c98 --- /dev/null +++ b/src/Squidex.Web/ContextExtensions.cs @@ -0,0 +1,37 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Microsoft.AspNetCore.Http; +using Squidex.Domain.Apps.Entities; + +namespace Squidex.Web +{ + public static class ContextExtensions + { + public static Context Context(this HttpContext httpContext) + { + var context = httpContext.Features.Get(); + + if (context == null) + { + context = new Context { User = httpContext.User }; + + foreach (var header in httpContext.Request.Headers) + { + if (header.Key.StartsWith("X-", System.StringComparison.Ordinal)) + { + context.Headers.Add(header.Key, header.Value.ToString()); + } + } + + httpContext.Features.Set(context); + } + + return context; + } + } +} diff --git a/src/Squidex.Web/ContextProvider.cs b/src/Squidex.Web/ContextProvider.cs new file mode 100644 index 000000000..44f1f0a08 --- /dev/null +++ b/src/Squidex.Web/ContextProvider.cs @@ -0,0 +1,30 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Microsoft.AspNetCore.Http; +using Squidex.Domain.Apps.Entities; +using Squidex.Infrastructure; + +namespace Squidex.Web +{ + public sealed class ContextProvider : IContextProvider + { + private readonly IHttpContextAccessor httpContextAccessor; + + public Context Context + { + get { return httpContextAccessor.HttpContext.Context(); } + } + + public ContextProvider(IHttpContextAccessor httpContextAccessor) + { + Guard.NotNull(httpContextAccessor, nameof(httpContextAccessor)); + + this.httpContextAccessor = httpContextAccessor; + } + } +} diff --git a/src/Squidex.Web/EntityCreatedDto.cs b/src/Squidex.Web/EntityCreatedDto.cs index 95738823d..754f33f77 100644 --- a/src/Squidex.Web/EntityCreatedDto.cs +++ b/src/Squidex.Web/EntityCreatedDto.cs @@ -15,7 +15,7 @@ namespace Squidex.Web [Required] [Display(Description = "Id of the created entity.")] public string Id { get; set; } - + [Display(Description = "The new version of the entity.")] public long Version { get; set; } diff --git a/src/Squidex.Web/ErrorDto.cs b/src/Squidex.Web/ErrorDto.cs index 2d3e8f6be..2a8bda377 100644 --- a/src/Squidex.Web/ErrorDto.cs +++ b/src/Squidex.Web/ErrorDto.cs @@ -14,10 +14,10 @@ namespace Squidex.Web [Required] [Display(Description = "Error message.")] public string Message { get; set; } - + [Display(Description = "Detailed error messages.")] public string[] Details { get; set; } - + [Display(Description = "Status code of the http response.")] public int? StatusCode { get; set; } = 400; } diff --git a/src/Squidex.Web/PermissionExtensions.cs b/src/Squidex.Web/PermissionExtensions.cs index ab63f14f8..5001c8838 100644 --- a/src/Squidex.Web/PermissionExtensions.cs +++ b/src/Squidex.Web/PermissionExtensions.cs @@ -7,34 +7,14 @@ using Microsoft.AspNetCore.Http; using Squidex.Infrastructure.Security; -using Squidex.Shared.Identity; namespace Squidex.Web { public static class PermissionExtensions { - private sealed class PermissionFeature - { - public PermissionSet Permissions { get; } - - public PermissionFeature(PermissionSet permissions) - { - Permissions = permissions; - } - } - public static PermissionSet Permissions(this HttpContext httpContext) { - var feature = httpContext.Features.Get(); - - if (feature == null) - { - feature = new PermissionFeature(httpContext.User.Permissions()); - - httpContext.Features.Set(feature); - } - - return feature.Permissions; + return httpContext.Context().Permissions; } public static bool HasPermission(this HttpContext httpContext, Permission permission, PermissionSet permissions = null) diff --git a/src/Squidex.Web/Pipeline/ApiCostsFilter.cs b/src/Squidex.Web/Pipeline/ApiCostsFilter.cs index 0859a26c3..9f1241dad 100644 --- a/src/Squidex.Web/Pipeline/ApiCostsFilter.cs +++ b/src/Squidex.Web/Pipeline/ApiCostsFilter.cs @@ -47,15 +47,15 @@ namespace Squidex.Web.Pipeline { context.HttpContext.Features.Set(FilterDefinition); - var appFeature = context.HttpContext.Features.Get(); + var app = context.HttpContext.Context().App; - if (appFeature?.App != null && FilterDefinition.Weight > 0) + if (app != null && FilterDefinition.Weight > 0) { - var appId = appFeature.App.Id.ToString(); + var appId = app.Id.ToString(); using (Profiler.Trace("CheckUsage")) { - var plan = appPlansProvider.GetPlanForApp(appFeature.App); + var plan = appPlansProvider.GetPlanForApp(app); var usage = await usageTracker.GetMonthlyCallsAsync(appId, DateTime.Today); diff --git a/src/Squidex.Web/Pipeline/AppResolver.cs b/src/Squidex.Web/Pipeline/AppResolver.cs index 97e4e8f1e..25331c6f7 100644 --- a/src/Squidex.Web/Pipeline/AppResolver.cs +++ b/src/Squidex.Web/Pipeline/AppResolver.cs @@ -23,16 +23,6 @@ namespace Squidex.Web.Pipeline { private readonly IAppProvider appProvider; - public class AppFeature : IAppFeature - { - public IAppEntity App { get; } - - public AppFeature(IAppEntity app) - { - App = app; - } - } - public AppResolver(IAppProvider appProvider) { this.appProvider = appProvider; @@ -76,15 +66,15 @@ namespace Squidex.Web.Pipeline } } - var set = user.Permissions(); + var permissionSet = user.Permissions(); - if (!set.Includes(Permissions.ForApp(Permissions.App, appName))&& !AllowAnonymous(context)) + context.HttpContext.Context().App = app; + + if (!permissionSet.Includes(Permissions.ForApp(Permissions.App, appName)) && !AllowAnonymous(context)) { context.Result = new NotFoundResult(); return; } - - context.HttpContext.Features.Set(new AppFeature(app)); } await next(); diff --git a/src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs b/src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs index c2e3c7006..bb754447f 100644 --- a/src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs +++ b/src/Squidex.Web/Pipeline/RequestLogPerformanceMiddleware.cs @@ -47,9 +47,9 @@ namespace Squidex.Web.Pipeline } } - private static void LogFilters(HttpContext context, IObjectWriter c) + private static void LogFilters(HttpContext httpContext, IObjectWriter c) { - var app = context.Features.Get()?.App; + var app = httpContext.Context().App; if (app != null) { @@ -57,21 +57,21 @@ namespace Squidex.Web.Pipeline c.WriteProperty("appName", app.Name); } - var userId = context.User.OpenIdSubject(); + var userId = httpContext.User.OpenIdSubject(); if (!string.IsNullOrWhiteSpace(userId)) { c.WriteProperty(nameof(userId), userId); } - var clientId = context.User.OpenIdClientId(); + var clientId = httpContext.User.OpenIdClientId(); if (!string.IsNullOrWhiteSpace(clientId)) { c.WriteProperty(nameof(clientId), clientId); } - var costs = context.Features.Get()?.Weight ?? 0; + var costs = httpContext.Features.Get()?.Weight ?? 0; c.WriteProperty(nameof(costs), costs); } diff --git a/src/Squidex.Web/Resource.cs b/src/Squidex.Web/Resource.cs index 31602a124..9719dfd1d 100644 --- a/src/Squidex.Web/Resource.cs +++ b/src/Squidex.Web/Resource.cs @@ -5,10 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Newtonsoft.Json; -using Squidex.Infrastructure; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; +using Squidex.Infrastructure; namespace Squidex.Web { diff --git a/src/Squidex.Web/ResourceLink.cs b/src/Squidex.Web/ResourceLink.cs index 2d2b4c0c5..ef54bfa98 100644 --- a/src/Squidex.Web/ResourceLink.cs +++ b/src/Squidex.Web/ResourceLink.cs @@ -17,7 +17,7 @@ namespace Squidex.Web [Required] [Display(Description = "The link method.")] - public string Method { get; set; } + public string Method { get; set; } [Required] [Display(Description = "Additional data about the link.")] diff --git a/src/Squidex.Web/Squidex.Web.csproj b/src/Squidex.Web/Squidex.Web.csproj index bbe645f13..2c9404cb7 100644 --- a/src/Squidex.Web/Squidex.Web.csproj +++ b/src/Squidex.Web/Squidex.Web.csproj @@ -9,6 +9,8 @@ + + diff --git a/src/Squidex.Web/UrlHelperExtensions.cs b/src/Squidex.Web/UrlHelperExtensions.cs index a4bc9280d..8d59cba5f 100644 --- a/src/Squidex.Web/UrlHelperExtensions.cs +++ b/src/Squidex.Web/UrlHelperExtensions.cs @@ -5,8 +5,10 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Microsoft.AspNetCore.Mvc; using System; +using Microsoft.AspNetCore.Mvc; + +#pragma warning disable RECS0108 // Warns about static fields in generic types namespace Squidex.Web { @@ -22,7 +24,7 @@ namespace Squidex.Web var name = typeof(T).Name; - if (name.EndsWith(suffix)) + if (name.EndsWith(suffix, StringComparison.Ordinal)) { name = name.Substring(0, name.Length - suffix.Length); } diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs new file mode 100644 index 000000000..be489f20e --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cs @@ -0,0 +1,86 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; +using Squidex.Areas.Api.Controllers.Apps.Models; +using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Infrastructure.Commands; +using Squidex.Shared; +using Squidex.Web; + +namespace Squidex.Areas.Api.Controllers.Apps +{ + /// + /// Manages and configures apps. + /// + [ApiExplorerSettings(GroupName = nameof(Apps))] + public sealed class AppWorkflowsController : ApiController + { + public AppWorkflowsController(ICommandBus commandBus) + : base(commandBus) + { + } + + /// + /// Get app workflow. + /// + /// The name of the app. + /// + /// 200 => App workflows returned. + /// 404 => App not found. + /// + [HttpGet] + [Route("apps/{app}/workflow/")] + [ProducesResponseType(typeof(WorkflowResponseDto), 200)] + [ApiPermission(Permissions.AppWorkflowsRead)] + [ApiCosts(0)] + public IActionResult GetWorkflow(string app) + { + var response = WorkflowResponseDto.FromApp(App, this); + + Response.Headers[HeaderNames.ETag] = App.Version.ToString(); + + return Ok(response); + } + + /// + /// Configure workflow of the app. + /// + /// The name of the app. + /// The new workflow. + /// + /// 200 => Workflow configured. + /// 400 => Workflow is not valid. + /// 404 => App not found. + /// + [HttpPut] + [Route("apps/{app}/workflow/")] + [ProducesResponseType(typeof(WorkflowResponseDto), 200)] + [ApiPermission(Permissions.AppWorkflowsUpdate)] + [ApiCosts(1)] + public async Task PutWorkflow(string app, [FromBody] UpsertWorkflowDto request) + { + var command = request.ToCommand(); + + var response = await InvokeCommandAsync(command); + + return Ok(response); + } + + private async Task InvokeCommandAsync(ICommand command) + { + var context = await CommandBus.PublishAsync(command); + + var result = context.Result(); + var response = WorkflowResponseDto.FromApp(result, this); + + return response; + } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs b/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs index 6d706dc30..46e37a1ea 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs @@ -177,6 +177,11 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models AddGetLink("schemas", controller.Url(x => nameof(x.GetSchemas), values)); } + if (controller.HasPermission(AllPermissions.AppWorkflowsRead, Name, permissions: permissions)) + { + AddGetLink("workflows", controller.Url(x => nameof(x.GetWorkflow), values)); + } + if (controller.HasPermission(AllPermissions.AppSchemasCreate, Name, permissions: permissions)) { AddPostLink("schemas/create", controller.Url(x => nameof(x.PostSchema), values)); diff --git a/src/Squidex/Areas/Api/Controllers/Apps/Models/UpsertWorkflowDto.cs b/src/Squidex/Areas/Api/Controllers/Apps/Models/UpsertWorkflowDto.cs new file mode 100644 index 000000000..d808c60b6 --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Apps/Models/UpsertWorkflowDto.cs @@ -0,0 +1,45 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Entities.Apps.Commands; + +namespace Squidex.Areas.Api.Controllers.Apps.Models +{ + public sealed class UpsertWorkflowDto + { + /// + /// The workflow steps. + /// + [Required] + public Dictionary Steps { get; set; } + + /// + /// The initial step. + /// + public Status Initial { get; set; } + + public ConfigureWorkflow ToCommand() + { + var workflow = new Workflow( + Steps?.ToDictionary( + x => x.Key, + x => new WorkflowStep( + x.Value?.Transitions.ToDictionary( + y => y.Key, + y => new WorkflowTransition(y.Value.Expression, y.Value.Role)), + x.Value.Color, + x.Value.NoUpdate)), + Initial); + + return new ConfigureWorkflow { Workflow = workflow }; + } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs new file mode 100644 index 000000000..3a6a3fecc --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs @@ -0,0 +1,61 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure.Reflection; +using Squidex.Shared; +using Squidex.Web; + +namespace Squidex.Areas.Api.Controllers.Apps.Models +{ + public sealed class WorkflowDto : Resource + { + /// + /// The workflow steps. + /// + [Required] + public Dictionary Steps { get; set; } + + /// + /// The initial step. + /// + public Status Initial { get; set; } + + public static WorkflowDto FromWorkflow(Workflow workflow, ApiController controller, string app) + { + var result = new WorkflowDto + { + Steps = workflow.Steps.ToDictionary( + x => x.Key, + x => SimpleMapper.Map(x.Value, new WorkflowStepDto + { + Transitions = x.Value.Transitions.ToDictionary( + y => y.Key, + y => new WorkflowTransitionDto { Expression = y.Value.Expression, Role = y.Value.Role }) + })), + Initial = workflow.Initial + }; + + return result.CreateLinks(controller, app); + } + + private WorkflowDto CreateLinks(ApiController controller, string app) + { + var values = new { app }; + + if (controller.HasPermission(Permissions.AppWorkflowsUpdate, app)) + { + AddPutLink("update", controller.Url(x => nameof(x.PutWorkflow), values)); + } + + return this; + } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowResponseDto.cs b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowResponseDto.cs new file mode 100644 index 000000000..3186a7893 --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowResponseDto.cs @@ -0,0 +1,32 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.ComponentModel.DataAnnotations; +using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Web; + +namespace Squidex.Areas.Api.Controllers.Apps.Models +{ + public sealed class WorkflowResponseDto : Resource + { + /// + /// The workflow. + /// + [Required] + public WorkflowDto Workflow { get; set; } + + public static WorkflowResponseDto FromApp(IAppEntity app, ApiController controller) + { + var result = new WorkflowResponseDto + { + Workflow = WorkflowDto.FromWorkflow(app.Workflows.GetFirst(), controller, app.Name) + }; + + return result; + } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs new file mode 100644 index 000000000..9012d406d --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs @@ -0,0 +1,32 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Squidex.Domain.Apps.Core.Contents; + +namespace Squidex.Areas.Api.Controllers.Apps.Models +{ + public sealed class WorkflowStepDto + { + /// + /// The transitions. + /// + [Required] + public Dictionary Transitions { get; set; } + + /// + /// The optional color. + /// + public string Color { get; set; } + + /// + /// Indicates if updates should not be allowed. + /// + public bool NoUpdate { get; set; } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowTransitionDto.cs b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowTransitionDto.cs new file mode 100644 index 000000000..94235a60d --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowTransitionDto.cs @@ -0,0 +1,22 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Areas.Api.Controllers.Apps.Models +{ + public sealed class WorkflowTransitionDto + { + /// + /// The optional expression. + /// + public string Expression { get; set; } + + /// + /// The optional restricted role. + /// + public string Role { get; set; } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs index 75b9867a7..38faed8f3 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs @@ -101,9 +101,7 @@ namespace Squidex.Areas.Api.Controllers.Assets [ApiCosts(1)] public async Task GetAssets(string app, [FromQuery] string ids = null) { - var context = Context(); - - var assets = await assetQuery.QueryAsync(context, Q.Empty.WithODataQuery(Request.QueryString.ToString()).WithIds(ids)); + var assets = await assetQuery.QueryAsync(Context, Q.Empty.WithODataQuery(Request.QueryString.ToString()).WithIds(ids)); var response = AssetsDto.FromAssets(assets, this, app); @@ -304,10 +302,5 @@ namespace Squidex.Areas.Api.Controllers.Assets return assetFile; } - - private QueryContext Context() - { - return QueryContext.Create(App, User); - } } } diff --git a/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs b/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs index 6885ce6cf..095be8d07 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs @@ -62,7 +62,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(2)] public async Task PostGraphQL(string app, [FromBody] GraphQLQuery query) { - var result = await graphQl.QueryAsync(Context(), query); + var result = await graphQl.QueryAsync(Context, query); if (result.HasError) { @@ -93,7 +93,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(2)] public async Task PostGraphQLBatch(string app, [FromBody] GraphQLQuery[] batch) { - var result = await graphQl.QueryAsync(Context(), batch); + var result = await graphQl.QueryAsync(Context, batch); if (result.HasError) { @@ -124,17 +124,16 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task GetAllContents(string app, [FromQuery] string ids) { - var context = Context(); - var contents = await contentQuery.QueryAsync(context, Q.Empty.WithIds(ids).Ids); + var contents = await contentQuery.QueryAsync(Context, Q.Empty.WithIds(ids).Ids); - var response = await ContentsDto.FromContentsAsync(contents, context, this, null, contentWorkflow); + var response = await ContentsDto.FromContentsAsync(contents, Context, this, null, contentWorkflow); if (controllerOptions.Value.EnableSurrogateKeys && response.Items.Length <= controllerOptions.Value.MaxItemsForSurrogateKeys) { Response.Headers["Surrogate-Key"] = response.ToSurrogateKeys(); } - Response.Headers[HeaderNames.ETag] = response.ToEtag(); + Response.Headers[HeaderNames.ETag] = $"{response.ToEtag()}_{App.Version}"; return Ok(response); } @@ -159,19 +158,18 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task GetContents(string app, string name, [FromQuery] string ids = null) { - var context = Context(); - var contents = await contentQuery.QueryAsync(context, name, Q.Empty.WithIds(ids).WithODataQuery(Request.QueryString.ToString())); + var contents = await contentQuery.QueryAsync(Context, name, Q.Empty.WithIds(ids).WithODataQuery(Request.QueryString.ToString())); - var schema = await contentQuery.GetSchemaOrThrowAsync(context, name); + var schema = await contentQuery.GetSchemaOrThrowAsync(Context, name); - var response = await ContentsDto.FromContentsAsync(contents, context, this, schema, contentWorkflow); + var response = await ContentsDto.FromContentsAsync(contents, Context, this, schema, contentWorkflow); if (ShouldProvideSurrogateKeys(response)) { Response.Headers["Surrogate-Key"] = response.ToSurrogateKeys(); } - Response.Headers[HeaderNames.ETag] = response.ToEtag(); + Response.Headers[HeaderNames.ETag] = $"{response.ToEtag()}_{App.Version}"; return Ok(response); } @@ -196,17 +194,16 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task GetContent(string app, string name, Guid id) { - var context = Context(); - var content = await contentQuery.FindContentAsync(context, name, id); + var content = await contentQuery.FindContentAsync(Context, name, id); - var response = ContentDto.FromContent(context, content, this); + var response = ContentDto.FromContent(Context, content, this); if (controllerOptions.Value.EnableSurrogateKeys) { Response.Headers["Surrogate-Key"] = content.Id.ToString(); } - Response.Headers[HeaderNames.ETag] = content.Version.ToString(); + Response.Headers[HeaderNames.ETag] = $"{response.ToEtag()}_{App.Version}"; return Ok(response); } @@ -232,17 +229,16 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task GetContentVersion(string app, string name, Guid id, int version) { - var context = Context(); - var content = await contentQuery.FindContentAsync(context, name, id, version); + var content = await contentQuery.FindContentAsync(Context, name, id, version); - var response = ContentDto.FromContent(context, content, this); + var response = ContentDto.FromContent(Context, content, this); if (controllerOptions.Value.EnableSurrogateKeys) { Response.Headers["Surrogate-Key"] = content.Id.ToString(); } - Response.Headers[HeaderNames.ETag] = content.Version.ToString(); + Response.Headers[HeaderNames.ETag] = $"{response.ToEtag()}_{App.Version}"; return Ok(response.Data); } @@ -269,7 +265,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task PostContent(string app, string name, [FromBody] NamedContentData request, [FromQuery] bool publish = false) { - await contentQuery.GetSchemaOrThrowAsync(Context(), name); + await contentQuery.GetSchemaOrThrowAsync(Context, name); if (publish && !this.HasPermission(Helper.StatusPermission(app, name, Status.Published))) { @@ -306,7 +302,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task PutContent(string app, string name, Guid id, [FromBody] NamedContentData request, [FromQuery] bool asDraft = false) { - await contentQuery.GetSchemaOrThrowAsync(Context(), name); + await contentQuery.GetSchemaOrThrowAsync(Context, name); var command = new UpdateContent { ContentId = id, Data = request.ToCleaned(), AsDraft = asDraft }; @@ -338,7 +334,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task PatchContent(string app, string name, Guid id, [FromBody] NamedContentData request, [FromQuery] bool asDraft = false) { - await contentQuery.GetSchemaOrThrowAsync(Context(), name); + await contentQuery.GetSchemaOrThrowAsync(Context, name); var command = new PatchContent { ContentId = id, Data = request.ToCleaned(), AsDraft = asDraft }; @@ -369,7 +365,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task PutContentStatus(string app, string name, Guid id, ChangeStatusDto request) { - await contentQuery.GetSchemaOrThrowAsync(Context(), name); + await contentQuery.GetSchemaOrThrowAsync(Context, name); if (!this.HasPermission(Helper.StatusPermission(app, name, Status.Published))) { @@ -404,7 +400,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task DiscardDraft(string app, string name, Guid id) { - await contentQuery.GetSchemaOrThrowAsync(Context(), name); + await contentQuery.GetSchemaOrThrowAsync(Context, name); var command = new DiscardChanges { ContentId = id }; @@ -432,7 +428,7 @@ namespace Squidex.Areas.Api.Controllers.Contents [ApiCosts(1)] public async Task DeleteContent(string app, string name, Guid id) { - await contentQuery.GetSchemaOrThrowAsync(Context(), name); + await contentQuery.GetSchemaOrThrowAsync(Context, name); var command = new DeleteContent { ContentId = id }; @@ -446,20 +442,11 @@ namespace Squidex.Areas.Api.Controllers.Contents var context = await CommandBus.PublishAsync(command); var result = context.Result(); - var response = ContentDto.FromContent(null, result, this); + var response = ContentDto.FromContent(Context, result, this); return response; } - private QueryContext Context() - { - return QueryContext.Create(App, User) - .WithAssetUrlsToResolve(Request.Headers["X-Resolve-Urls"]) - .WithFlatten(Request.Headers.ContainsKey("X-Flatten")) - .WithLanguages(Request.Headers["X-Languages"]) - .WithUnpublished(Request.Headers.ContainsKey("X-Unpublished")); - } - private bool ShouldProvideSurrogateKeys(ContentsDto response) { return controllerOptions.Value.EnableSurrogateKeys && response.Items.Length <= controllerOptions.Value.MaxItemsForSurrogateKeys; diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs index 26440c83f..0725239e4 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs @@ -84,11 +84,11 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// public long Version { get; set; } - public static ContentDto FromContent(QueryContext context, IEnrichedContentEntity content, ApiController controller) + public static ContentDto FromContent(Context context, IEnrichedContentEntity content, ApiController controller) { var response = SimpleMapper.Map(content, new ContentDto()); - if (context?.Flatten == true) + if (context.IsFlatten()) { response.Data = content.Data?.ToFlatten(); response.DataDraft = content.DataDraft?.ToFlatten(); @@ -153,11 +153,14 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models AddDeleteLink("delete", controller.Url(x => nameof(x.DeleteContent), values)); } - foreach (var next in content.Nexts) + if (content.Nexts != null) { - if (controller.HasPermission(Helper.StatusPermission(app, schema, next.Status))) + foreach (var next in content.Nexts) { - AddPutLink($"status/{next.Status}", controller.Url(x => nameof(x.PutContentStatus), values), next.Color); + if (controller.HasPermission(Helper.StatusPermission(app, schema, next.Status))) + { + AddPutLink($"status/{next.Status}", controller.Url(x => nameof(x.PutContentStatus), values), next.Color); + } } } diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs index c81ec7b0e..749e662d1 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs @@ -48,7 +48,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models } public static async Task FromContentsAsync(IResultList contents, - QueryContext context, ApiController controller, ISchemaEntity schema, IContentWorkflow contentWorkflow) + Context context, ApiController controller, ISchemaEntity schema, IContentWorkflow contentWorkflow) { var result = new ContentsDto { diff --git a/src/Squidex/Areas/Api/Controllers/UI/UIController.cs b/src/Squidex/Areas/Api/Controllers/UI/UIController.cs index e07d9f23e..3ca2f79fb 100644 --- a/src/Squidex/Areas/Api/Controllers/UI/UIController.cs +++ b/src/Squidex/Areas/Api/Controllers/UI/UIController.cs @@ -16,7 +16,6 @@ using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Orleans; using Squidex.Infrastructure.Security; using Squidex.Shared; -using Squidex.Shared.Identity; using Squidex.Web; namespace Squidex.Areas.Api.Controllers.UI @@ -53,7 +52,7 @@ namespace Squidex.Areas.Api.Controllers.UI MapKey = uiOptions.Map?.GoogleMaps?.Key }; - var canCreateApps = !uiOptions.OnlyAdminsCanCreateApps || User.Permissions().Includes(CreateAppPermission); + var canCreateApps = !uiOptions.OnlyAdminsCanCreateApps || Context.Permissions.Includes(CreateAppPermission); result.CanCreateApps = canCreateApps; diff --git a/src/Squidex/Config/Domain/EntitiesServices.cs b/src/Squidex/Config/Domain/EntitiesServices.cs index ce886628c..47c2e44b9 100644 --- a/src/Squidex/Config/Domain/EntitiesServices.cs +++ b/src/Squidex/Config/Domain/EntitiesServices.cs @@ -120,7 +120,7 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); - services.AddSingletonAs() + services.AddSingletonAs() .AsOptional(); services.AddSingletonAs() diff --git a/src/Squidex/Config/Domain/SerializationServices.cs b/src/Squidex/Config/Domain/SerializationServices.cs index 44aadc738..9217ff2fb 100644 --- a/src/Squidex/Config/Domain/SerializationServices.cs +++ b/src/Squidex/Config/Domain/SerializationServices.cs @@ -46,7 +46,8 @@ namespace Squidex.Config.Domain new RuleConverter(), new SchemaConverter(), new StatusConverter(), - new StringEnumConverter()); + new StringEnumConverter(), + new WorkflowConverter()); settings.NullValueHandling = NullValueHandling.Ignore; diff --git a/src/Squidex/Config/Web/WebServices.cs b/src/Squidex/Config/Web/WebServices.cs index ec55d161a..580b214ad 100644 --- a/src/Squidex/Config/Web/WebServices.cs +++ b/src/Squidex/Config/Web/WebServices.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Squidex.Config.Domain; +using Squidex.Domain.Apps.Entities; using Squidex.Pipeline.Plugins; using Squidex.Pipeline.Robots; using Squidex.Web; @@ -41,6 +42,9 @@ namespace Squidex.Config.Web services.AddSingletonAs() .AsSelf(); + services.AddSingletonAs() + .As(); + services.AddSingletonAs() .As(); diff --git a/src/Squidex/app/features/administration/module.ts b/src/Squidex/app/features/administration/module.ts index a97719a34..b130cb62f 100644 --- a/src/Squidex/app/features/administration/module.ts +++ b/src/Squidex/app/features/administration/module.ts @@ -87,4 +87,4 @@ const routes: Routes = [ UsersState ] }) -export class SqxFeatureAdministrationModule { } \ No newline at end of file +export class SqxFeatureAdministrationModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/administration/services/event-consumers.service.ts b/src/Squidex/app/features/administration/services/event-consumers.service.ts index 18ebdc7ca..2aa592765 100644 --- a/src/Squidex/app/features/administration/services/event-consumers.service.ts +++ b/src/Squidex/app/features/administration/services/event-consumers.service.ts @@ -62,12 +62,12 @@ export class EventConsumersService { const url = this.apiUrl.buildUrl('/api/event-consumers'); return this.http.get<{ items: any[] } & Resource>(url).pipe( - map(({ items, _links }) => { - const eventConsumers = items.map(item => parseEventConsumer(item)); + map(({ items, _links }) => { + const eventConsumers = items.map(item => parseEventConsumer(item)); - return new EventConsumersDto(eventConsumers, _links); - }), - pretifyError('Failed to load event consumers. Please reload.')); + return new EventConsumersDto(eventConsumers, _links); + }), + pretifyError('Failed to load event consumers. Please reload.')); } public putStart(eventConsumer: Resource): Observable { @@ -76,10 +76,10 @@ export class EventConsumersService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url).pipe( - map(body => { - return parseEventConsumer(body); - }), - pretifyError('Failed to start event consumer. Please reload.')); + map(body => { + return parseEventConsumer(body); + }), + pretifyError('Failed to start event consumer. Please reload.')); } public putStop(eventConsumer: Resource): Observable { @@ -88,10 +88,10 @@ export class EventConsumersService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url).pipe( - map(body => { - return parseEventConsumer(body); - }), - pretifyError('Failed to stop event consumer. Please reload.')); + map(body => { + return parseEventConsumer(body); + }), + pretifyError('Failed to stop event consumer. Please reload.')); } public putReset(eventConsumer: Resource): Observable { @@ -100,10 +100,10 @@ export class EventConsumersService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url).pipe( - map(body => { - return parseEventConsumer(body); - }), - pretifyError('Failed to reset event consumer. Please reload.')); + map(body => { + return parseEventConsumer(body); + }), + pretifyError('Failed to reset event consumer. Please reload.')); } } diff --git a/src/Squidex/app/features/administration/services/users.service.ts b/src/Squidex/app/features/administration/services/users.service.ts index 4992334f1..3d6cc1a05 100644 --- a/src/Squidex/app/features/administration/services/users.service.ts +++ b/src/Squidex/app/features/administration/services/users.service.ts @@ -19,7 +19,7 @@ import { ResultSet } from '@app/shared'; -export class UsersDto extends ResultSet { +export class UsersDto extends ResultSet { public get canCreate() { return hasAnyLink(this._links, 'create'); } @@ -73,32 +73,32 @@ export class UsersService { 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(item => parseUser(item)); + map(({ total, items, _links }) => { + const users = items.map(item => parseUser(item)); - return new UsersDto(total, users, _links); - }), - pretifyError('Failed to load users. Please reload.')); + return new UsersDto(total, users, _links); + }), + pretifyError('Failed to load users. Please reload.')); } public getUser(id: string): Observable { const url = this.apiUrl.buildUrl(`api/user-management/${id}`); return this.http.get(url).pipe( - map(body => { - return parseUser(body); - }), - pretifyError('Failed to load user. Please reload.')); + map(body => { + return parseUser(body); + }), + pretifyError('Failed to load user. Please reload.')); } public postUser(dto: CreateUserDto): Observable { const url = this.apiUrl.buildUrl('api/user-management'); return this.http.post(url, dto).pipe( - map(body => { - return parseUser(body); - }), - pretifyError('Failed to create user. Please reload.')); + map(body => { + return parseUser(body); + }), + pretifyError('Failed to create user. Please reload.')); } public putUser(user: Resource, dto: UpdateUserDto): Observable { @@ -107,10 +107,10 @@ export class UsersService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url, { body: dto }).pipe( - map(body => { - return parseUser(body); - }), - pretifyError('Failed to update user. Please reload.')); + map(body => { + return parseUser(body); + }), + pretifyError('Failed to update user. Please reload.')); } public lockUser(user: Resource): Observable { @@ -119,10 +119,10 @@ export class UsersService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url).pipe( - map(body => { - return parseUser(body); - }), - pretifyError('Failed to load users. Please retry.')); + map(body => { + return parseUser(body); + }), + pretifyError('Failed to load users. Please retry.')); } public unlockUser(user: Resource): Observable { @@ -131,10 +131,10 @@ export class UsersService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url).pipe( - map(body => { - return parseUser(body); - }), - pretifyError('Failed to load users. Please retry.')); + map(body => { + return parseUser(body); + }), + pretifyError('Failed to load users. Please retry.')); } } diff --git a/src/Squidex/app/features/api/module.ts b/src/Squidex/app/features/api/module.ts index f4701b425..471c3efd6 100644 --- a/src/Squidex/app/features/api/module.ts +++ b/src/Squidex/app/features/api/module.ts @@ -45,4 +45,4 @@ const routes: Routes = [ GraphQLPageComponent ] }) -export class SqxFeatureApiModule { } \ No newline at end of file +export class SqxFeatureApiModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/apps/module.ts b/src/Squidex/app/features/apps/module.ts index 16387df1f..cf43f604e 100644 --- a/src/Squidex/app/features/apps/module.ts +++ b/src/Squidex/app/features/apps/module.ts @@ -35,4 +35,4 @@ const routes: Routes = [ OnboardingDialogComponent ] }) -export class SqxFeatureAppsModule { } \ No newline at end of file +export class SqxFeatureAppsModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/assets/module.ts b/src/Squidex/app/features/assets/module.ts index 755987200..bcfb24292 100644 --- a/src/Squidex/app/features/assets/module.ts +++ b/src/Squidex/app/features/assets/module.ts @@ -39,4 +39,4 @@ const routes: Routes = [ AssetsPageComponent ] }) -export class SqxFeatureAssetsModule { } \ No newline at end of file +export class SqxFeatureAssetsModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/content/module.ts b/src/Squidex/app/features/content/module.ts index 4c6f8a9d1..488f2a6c5 100644 --- a/src/Squidex/app/features/content/module.ts +++ b/src/Squidex/app/features/content/module.ts @@ -128,4 +128,4 @@ const routes: Routes = [ SchemasPageComponent ] }) -export class SqxFeatureContentModule { } \ No newline at end of file +export class SqxFeatureContentModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/dashboard/module.ts b/src/Squidex/app/features/dashboard/module.ts index 0942cc3b6..d821eb1f6 100644 --- a/src/Squidex/app/features/dashboard/module.ts +++ b/src/Squidex/app/features/dashboard/module.ts @@ -33,4 +33,4 @@ const routes: Routes = [ DashboardPageComponent ] }) -export class SqxFeatureDashboardModule { } \ No newline at end of file +export class SqxFeatureDashboardModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/rules/module.ts b/src/Squidex/app/features/rules/module.ts index 7ee3218b3..78b84b860 100644 --- a/src/Squidex/app/features/rules/module.ts +++ b/src/Squidex/app/features/rules/module.ts @@ -66,4 +66,4 @@ const routes: Routes = [ UsageTriggerComponent ] }) -export class SqxFeatureRulesModule { } \ No newline at end of file +export class SqxFeatureRulesModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/schemas/module.ts b/src/Squidex/app/features/schemas/module.ts index b328efd96..ad7b2c59e 100644 --- a/src/Squidex/app/features/schemas/module.ts +++ b/src/Squidex/app/features/schemas/module.ts @@ -112,4 +112,4 @@ const routes: Routes = [ TagsValidationComponent ] }) -export class SqxFeatureSchemasModule { } \ No newline at end of file +export class SqxFeatureSchemasModule {} \ No newline at end of file diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html index 334bd3430..a141af0ea 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html @@ -25,10 +25,10 @@
-
+
diff --git a/src/Squidex/app/framework/angular/pipes/name.pipe.spec.ts b/src/Squidex/app/framework/angular/pipes/name.pipe.spec.ts index 72760d786..ab816a1f4 100644 --- a/src/Squidex/app/framework/angular/pipes/name.pipe.spec.ts +++ b/src/Squidex/app/framework/angular/pipes/name.pipe.spec.ts @@ -54,6 +54,6 @@ describe('DisplayNamePipe', () => { it('should return empty string if also fallback not found', () => { const pipe = new DisplayNamePipe(); - expect(pipe.transform({ })).toBe(''); + expect(pipe.transform({})).toBe(''); }); }); \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/routers/router-utils.ts b/src/Squidex/app/framework/angular/routers/router-utils.ts index d81393c22..ef6d0cff8 100644 --- a/src/Squidex/app/framework/angular/routers/router-utils.ts +++ b/src/Squidex/app/framework/angular/routers/router-utils.ts @@ -10,7 +10,7 @@ import { ActivatedRoute, ActivatedRouteSnapshot, Data, Params, RouterStateSnapsh export function allData(value: ActivatedRouteSnapshot | ActivatedRoute): Data { let snapshot: ActivatedRouteSnapshot | null = value['snapshot'] || value; - const result: { [key: string]: any } = { }; + const result: { [key: string]: any } = {}; while (snapshot) { for (let key in snapshot.data) { @@ -27,7 +27,7 @@ export function allData(value: ActivatedRouteSnapshot | ActivatedRoute): Data { export function allParams(value: ActivatedRouteSnapshot | ActivatedRoute): Params { let snapshot: ActivatedRouteSnapshot | null = value['snapshot'] || value; - const result: { [key: string]: any } = { }; + const result: { [key: string]: any } = {}; while (snapshot) { for (let key in snapshot.params) { diff --git a/src/Squidex/app/framework/angular/stateful.component.ts b/src/Squidex/app/framework/angular/stateful.component.ts index ec261fcfa..dcf50299e 100644 --- a/src/Squidex/app/framework/angular/stateful.component.ts +++ b/src/Squidex/app/framework/angular/stateful.component.ts @@ -113,36 +113,5 @@ export abstract class StatefulControlComponent extends StatefulCompon this.next(s => ({ ...s, isDisabled })); } - public abstract writeValue(obj: any): void; -} - -export abstract class ExternalControlComponent extends StatefulComponent implements ControlValueAccessor { - private fnChanged = (v: any) => { /* NOOP */ }; - private fnTouched = () => { /* NOOP */ }; - - constructor(changeDetector: ChangeDetectorRef) { - super(changeDetector, {}); - - changeDetector.detach(); - } - - public registerOnChange(fn: any) { - this.fnChanged = fn; - } - - public registerOnTouched(fn: any) { - this.fnTouched = fn; - } - - protected callTouched() { - this.fnTouched(); - } - - protected callChange(value: TValue) { - this.fnChanged(value); - } - - public abstract setDisabledState(isDisabled: boolean): void; - public abstract writeValue(obj: any): void; } \ No newline at end of file diff --git a/src/Squidex/app/framework/configurations.ts b/src/Squidex/app/framework/configurations.ts index f46f4857a..4bb75d0bf 100644 --- a/src/Squidex/app/framework/configurations.ts +++ b/src/Squidex/app/framework/configurations.ts @@ -35,13 +35,13 @@ export class CurrencyConfig { } export class AnalyticsIdConfig { - constructor(public value: string) { } + constructor(public value: string) {} } export class DecimalSeparatorConfig { - constructor(public readonly value: string) { } + constructor(public readonly value: string) {} } export class ProductionModeConfig { - constructor(public readonly isProductionMode: boolean) { } + constructor(public readonly isProductionMode: boolean) {} } \ No newline at end of file diff --git a/src/Squidex/app/framework/services/message-bus.service.spec.ts b/src/Squidex/app/framework/services/message-bus.service.spec.ts index 120b36cda..840f99b0c 100644 --- a/src/Squidex/app/framework/services/message-bus.service.spec.ts +++ b/src/Squidex/app/framework/services/message-bus.service.spec.ts @@ -7,8 +7,8 @@ import { MessageBus, MessageBusFactory } from './message-bus.service'; -class Event1 { } -class Event2 { } +class Event1 {} +class Event2 {} describe('MessageBus', () => { it('should instantiate from factory', () => { diff --git a/src/Squidex/app/framework/services/title.service.ts b/src/Squidex/app/framework/services/title.service.ts index 6cd37d9a2..7fa7e7f49 100644 --- a/src/Squidex/app/framework/services/title.service.ts +++ b/src/Squidex/app/framework/services/title.service.ts @@ -22,7 +22,7 @@ export const TitleServiceFactory = (titles: TitlesConfig) => { @Injectable() export class TitleService { - constructor(private readonly titles: TitlesConfig) { } + constructor(private readonly titles: TitlesConfig) {} public setTitle(key: string, parameters?: { [key: string]: string }) { let title = this.titles.value[key] || key; diff --git a/src/Squidex/app/framework/utils/immutable-array.ts b/src/Squidex/app/framework/utils/immutable-array.ts index a8becffe4..354b883b2 100644 --- a/src/Squidex/app/framework/utils/immutable-array.ts +++ b/src/Squidex/app/framework/utils/immutable-array.ts @@ -193,25 +193,11 @@ export class ImmutableArray implements Iterable { } export function compareStringsAsc(a: string, b: string) { - if (a < b) { - return -1; - } - if (a > b) { - return 1; - } - - return 0; + return a.localeCompare(b, undefined, { sensitivity: 'base' }); } export function compareStringsDesc(a: string, b: string) { - if (a < b) { - return 1; - } - if (a > b) { - return -1; - } - - return 0; + return b.localeCompare(a, undefined, { sensitivity: 'base' }); } export function compareNumbersAsc(a: number, b: number) { diff --git a/src/Squidex/app/framework/utils/interpolator.spec.ts b/src/Squidex/app/framework/utils/interpolator.spec.ts index 6da899ee1..19ffbb9f7 100644 --- a/src/Squidex/app/framework/utils/interpolator.spec.ts +++ b/src/Squidex/app/framework/utils/interpolator.spec.ts @@ -58,7 +58,7 @@ describe('interpolate', () => { }); it('should return undefined if it resolved to object', () => { - const result = interpolate('hello ${data}', { data: { } }); + const result = interpolate('hello ${data}', { data: {} }); expect(result).toEqual('hello undefined'); }); diff --git a/src/Squidex/app/framework/utils/math-helper.spec.ts b/src/Squidex/app/framework/utils/math-helper.spec.ts index 8c4fbde93..4d584cb3f 100644 --- a/src/Squidex/app/framework/utils/math-helper.spec.ts +++ b/src/Squidex/app/framework/utils/math-helper.spec.ts @@ -108,6 +108,54 @@ describe('MathHelper', () => { expect(color.a).toBe(0.5); }); + it('should convert from hsv with red', () => { + const color = MathHelper.colorFromHsv(0, 1, 1); + + expect(color.r).toBe(1); + expect(color.g).toBe(0); + expect(color.b).toBe(0); + }); + + it('should convert from hsv with yellow', () => { + const color = MathHelper.colorFromHsv(60, 1, 1); + + expect(color.r).toBe(1); + expect(color.g).toBe(1); + expect(color.b).toBe(0); + }); + + it('should convert from hsv with blue', () => { + const color = MathHelper.colorFromHsv(120, 1, 1); + + expect(color.r).toBe(0); + expect(color.g).toBe(1); + expect(color.b).toBe(0); + }); + + it('should convert from hsv with turkis', () => { + const color = MathHelper.colorFromHsv(180, 1, 1); + + expect(color.r).toBe(0); + expect(color.g).toBe(1); + expect(color.b).toBe(1); + }); + + it('should convert from hsv with red', () => { + const color = MathHelper.colorFromHsv(240, 1, 1); + + expect(color.r).toBe(0); + expect(color.g).toBe(0); + expect(color.b).toBe(1); + }); + + it('should convert from hsv with pink', () => { + const color = MathHelper.colorFromHsv(300, 1, 1); + + expect(color.r).toBe(1); + expect(color.g).toBe(0); + expect(color.b).toBe(1); + }); + it('should convert to luminance', () => { expect(MathHelper.toLuminance(undefined!)).toBe(1); @@ -116,4 +164,10 @@ describe('MathHelper', () => { expect(MathHelper.toLuminance({ r: 0.5, g: 0.5, b: 0.5, a: 1 })).toBe(0.5); }); + + it('should generate random color', () => { + const color = MathHelper.randomColor(); + + expect(color[0]).toEqual('#'); + }); }); diff --git a/src/Squidex/app/framework/utils/math-helper.ts b/src/Squidex/app/framework/utils/math-helper.ts index 419464081..0d733aa20 100644 --- a/src/Squidex/app/framework/utils/math-helper.ts +++ b/src/Squidex/app/framework/utils/math-helper.ts @@ -26,42 +26,35 @@ const ColorDefinitions: IColorDefinition[] = [ { regex: /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*([\d\.]{1,})\)$/, process: (bits) => { - return { - r: parseInt(bits[1], 10) / 255, - g: parseInt(bits[2], 10) / 255, - b: parseInt(bits[3], 10) / 255, - a: parseFloat(bits[4]) - }; + return createColor( + parseInt(bits[1], 10) / 255, + parseInt(bits[2], 10) / 255, + parseInt(bits[3], 10) / 255, + parseFloat(bits[4])); } }, { regex: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, process: (bits) => { - return { - r: parseInt(bits[1], 10) / 255, - g: parseInt(bits[2], 10) / 255, - b: parseInt(bits[3], 10) / 255, - a: 1 - }; + return createColor( + parseInt(bits[1], 10) / 255, + parseInt(bits[2], 10) / 255, + parseInt(bits[3], 10) / 255); } }, { regex: /^(\w{2})(\w{2})(\w{2})$/, process: (bits) => { - return { - r: parseInt(bits[1], 16) / 255, - g: parseInt(bits[2], 16) / 255, - b: parseInt(bits[3], 16) / 255, - a: 1 - }; + return createColor( + parseInt(bits[1], 16) / 255, + parseInt(bits[2], 16) / 255, + parseInt(bits[3], 16) / 255); } }, { regex: /^(\w{1})(\w{1})(\w{1})$/, process: (bits) => { - return { - r: parseInt(bits[1] + bits[1], 16) / 255, - g: parseInt(bits[2] + bits[2], 16) / 255, - b: parseInt(bits[3] + bits[3], 16) / 255, - a: 1 - }; + return createColor( + parseInt(bits[1] + bits[1], 16) / 255, + parseInt(bits[2] + bits[2], 16) / 255, + parseInt(bits[3] + bits[3], 16) / 255); } } ]; @@ -165,6 +158,53 @@ export module MathHelper { return undefined; } + export function randomColor() { + return colorToString(colorFromHsv(Math.random() * 360, .9, .9)); + } + + export function colorToString(color: Color): string { + let r = Math.round(color.r * 255).toString(16); + let g = Math.round(color.g * 255).toString(16); + let b = Math.round(color.b * 255).toString(16); + + if (r.length === 1) { + r = '0' + r; + } + if (g.length === 1) { + g = '0' + g; + } + if (b.length === 1) { + b = '0' + b; + } + + return '#' + r + g + b; + } + + export function colorFromHsv(h: number, s: number, v: number): Color { + const hi = Math.floor(h / 60) % 6; + + const f = (h / 60) - Math.floor(h / 60); + + const p = (v * (1 - s)); + const q = (v * (1 - (f * s))); + const t = (v * (1 - ((1 - f) * s))); + + switch (hi) { + case 0: + return createColor(v, t, p); + case 1: + return createColor(q, v, p); + case 2: + return createColor(p, v, t); + case 3: + return createColor(p, q, v); + case 4: + return createColor(t, p, v); + default: + return createColor(v, p, q); + } + } + export function toLuminance(color: Color) { if (!color) { return 1; @@ -172,4 +212,8 @@ export module MathHelper { return (0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b) / color.a; } +} + +export function createColor(r: number, g: number, b: number, a = 1) { + return { r, g, b, a }; } \ No newline at end of file diff --git a/src/Squidex/app/shared/components/help-markdown.pipe.ts b/src/Squidex/app/shared/components/help-markdown.pipe.ts index 929c0a0dd..641450208 100644 --- a/src/Squidex/app/shared/components/help-markdown.pipe.ts +++ b/src/Squidex/app/shared/components/help-markdown.pipe.ts @@ -11,7 +11,11 @@ import * as Marked from 'marked'; const renderer = new Marked.Renderer(); renderer.link = (href, title, text) => { - return `
${text} `; + if (!href.startsWith('http')) { + href = `https://docs.squidex.io/${href}`; + } + + return `${text} `; }; @Pipe({ diff --git a/src/Squidex/app/shared/components/rich-editor.component.html b/src/Squidex/app/shared/components/rich-editor.component.html index 44a1469e8..d4aaa1e17 100644 --- a/src/Squidex/app/shared/components/rich-editor.component.html +++ b/src/Squidex/app/shared/components/rich-editor.component.html @@ -1,5 +1,5 @@
-
+
Loading editor...
diff --git a/src/Squidex/app/shared/internal.ts b/src/Squidex/app/shared/internal.ts index f467a7636..71a0a1561 100644 --- a/src/Squidex/app/shared/internal.ts +++ b/src/Squidex/app/shared/internal.ts @@ -32,6 +32,7 @@ export * from './services/ui.service'; export * from './services/usages.service'; export * from './services/users-provider.service'; export * from './services/users.service'; +export * from './services/workflows.service'; export * from './state/apps.forms'; export * from './state/apps.state'; @@ -62,6 +63,7 @@ export * from './state/rules.state'; export * from './state/schemas.forms'; export * from './state/schemas.state'; export * from './state/ui.state'; +export * from './state/workflows.state'; export * from './utils/messages'; diff --git a/src/Squidex/app/shared/module.ts b/src/Squidex/app/shared/module.ts index 19fb7f461..76bd8171a 100644 --- a/src/Squidex/app/shared/module.ts +++ b/src/Squidex/app/shared/module.ts @@ -93,7 +93,9 @@ import { UserPicturePipe, UserPictureRefPipe, UsersProviderService, - UsersService + UsersService, + WorkflowsService, + WorkflowsState } from './declarations'; @NgModule({ @@ -224,6 +226,8 @@ export class SqxSharedModule { UsagesService, UsersProviderService, UsersService, + WorkflowsService, + WorkflowsState, { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, diff --git a/src/Squidex/app/shared/services/app-languages.service.ts b/src/Squidex/app/shared/services/app-languages.service.ts index 23a7a486e..eb13fb708 100644 --- a/src/Squidex/app/shared/services/app-languages.service.ts +++ b/src/Squidex/app/shared/services/app-languages.service.ts @@ -74,23 +74,23 @@ export class AppLanguagesService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages`); return HTTP.getVersioned(this.http, url).pipe( - mapVersioned(({ body }) => { - return parseLanguages(body); - }), - pretifyError('Failed to load languages. Please reload.')); + mapVersioned(({ body }) => { + return parseLanguages(body); + }), + pretifyError('Failed to load languages. Please reload.')); } public postLanguage(appName: string, dto: AddAppLanguageDto, version: Version): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/languages`); return HTTP.postVersioned(this.http, url, dto, version).pipe( - mapVersioned(({ body }) => { - return parseLanguages(body); - }), - tap(() => { - this.analytics.trackEvent('Language', 'Added', appName); - }), - pretifyError('Failed to add language. Please reload.')); + mapVersioned(({ body }) => { + return parseLanguages(body); + }), + tap(() => { + this.analytics.trackEvent('Language', 'Added', appName); + }), + pretifyError('Failed to add language. Please reload.')); } public putLanguage(appName: string, resource: Resource, dto: UpdateAppLanguageDto, version: Version): Observable { @@ -99,13 +99,13 @@ export class AppLanguagesService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe( - mapVersioned(({ body }) => { - return parseLanguages(body); - }), - tap(() => { - this.analytics.trackEvent('Language', 'Updated', appName); - }), - pretifyError('Failed to change language. Please reload.')); + mapVersioned(({ body }) => { + return parseLanguages(body); + }), + tap(() => { + this.analytics.trackEvent('Language', 'Updated', appName); + }), + pretifyError('Failed to change language. Please reload.')); } public deleteLanguage(appName: string, resource: Resource, version: Version): Observable { @@ -114,13 +114,13 @@ export class AppLanguagesService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version).pipe( - mapVersioned(({ body }) => { - return parseLanguages(body); - }), - tap(() => { - this.analytics.trackEvent('Language', 'Deleted', appName); - }), - pretifyError('Failed to add language. Please reload.')); + mapVersioned(({ body }) => { + return parseLanguages(body); + }), + tap(() => { + this.analytics.trackEvent('Language', 'Deleted', appName); + }), + pretifyError('Failed to add language. Please reload.')); } } diff --git a/src/Squidex/app/shared/services/apps.service.ts b/src/Squidex/app/shared/services/apps.service.ts index 090a23093..878bed2ad 100644 --- a/src/Squidex/app/shared/services/apps.service.ts +++ b/src/Squidex/app/shared/services/apps.service.ts @@ -35,7 +35,7 @@ export class AppDto { public readonly canReadRoles: boolean; public readonly canReadRules: boolean; public readonly canReadSchemas: boolean; - public readonly canReadWorkflows: boolean = true; + public readonly canReadWorkflows: boolean; public readonly canUploadAssets: boolean; constructor(links: ResourceLinks, @@ -63,6 +63,7 @@ export class AppDto { this.canReadRoles = hasAnyLink(links, 'roles'); this.canReadRules = hasAnyLink(links, 'rules'); this.canReadSchemas = hasAnyLink(links, 'schemas'); + this.canReadWorkflows = hasAnyLink(links, 'workflows'); this.canUploadAssets = hasAnyLink(links, 'assets/create'); } } @@ -85,25 +86,25 @@ export class AppsService { const url = this.apiUrl.buildUrl('/api/apps'); return this.http.get(url).pipe( - map(body => { - const apps = body.map(item => parseApp(item)); + map(body => { + const apps = body.map(item => parseApp(item)); - return apps; - }), - pretifyError('Failed to load apps. Please reload.')); + return apps; + }), + pretifyError('Failed to load apps. Please reload.')); } public postApp(dto: CreateAppDto): Observable { const url = this.apiUrl.buildUrl('api/apps'); return this.http.post(url, dto).pipe( - map(body => { - return parseApp(body); - }), - tap(() => { - this.analytics.trackEvent('App', 'Created', dto.name); - }), - pretifyError('Failed to create app. Please reload.')); + map(body => { + return parseApp(body); + }), + tap(() => { + this.analytics.trackEvent('App', 'Created', dto.name); + }), + pretifyError('Failed to create app. Please reload.')); } public deleteApp(resource: Resource): Observable { @@ -112,10 +113,10 @@ export class AppsService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url).pipe( - tap(() => { - this.analytics.trackEvent('App', 'Archived'); - }), - pretifyError('Failed to archive app. Please reload.')); + tap(() => { + this.analytics.trackEvent('App', 'Archived'); + }), + pretifyError('Failed to archive app. Please reload.')); } } diff --git a/src/Squidex/app/shared/services/assets.service.ts b/src/Squidex/app/shared/services/assets.service.ts index 8fd9e0fbd..b058e8a2d 100644 --- a/src/Squidex/app/shared/services/assets.service.ts +++ b/src/Squidex/app/shared/services/assets.service.ts @@ -138,12 +138,12 @@ export class AssetsService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets?${fullQuery}`); return this.http.get<{ total: number, items: any[] } & Resource>(url).pipe( - map(({ total, items, _links }) => { - const assets = items.map(item => parseAsset(item)); + map(({ total, items, _links }) => { + const assets = items.map(item => parseAsset(item)); - return new AssetsDto(total, assets, _links); - }), - pretifyError('Failed to load assets. Please reload.')); + return new AssetsDto(total, assets, _links); + }), + pretifyError('Failed to load assets. Please reload.')); } public uploadFile(appName: string, file: File): Observable { @@ -152,45 +152,45 @@ export class AssetsService { const req = new HttpRequest('POST', url, getFormData(file), { reportProgress: true }); return this.http.request(req).pipe( - filter(event => - event.type === HttpEventType.UploadProgress || - event.type === HttpEventType.Response), - map(event => { - if (event.type === HttpEventType.UploadProgress) { - const percentDone = event.total ? Math.round(100 * event.loaded / event.total) : 0; - - return percentDone; - } else if (Types.is(event, HttpResponse)) { - return parseAsset(event.body); - } else { - throw 'Invalid'; - } - }), - catchError((error: any) => { - if (Types.is(error, HttpErrorResponse) && error.status === 413) { - return throwError(new ErrorDto(413, 'Asset is too big.')); - } else { - return throwError(error); - } - }), - tap(value => { - if (!Types.isNumber(value)) { - this.analytics.trackEvent('Asset', 'Uploaded', appName); - } - }), - pretifyError('Failed to upload asset. Please reload.')); + filter(event => + event.type === HttpEventType.UploadProgress || + event.type === HttpEventType.Response), + map(event => { + if (event.type === HttpEventType.UploadProgress) { + const percentDone = event.total ? Math.round(100 * event.loaded / event.total) : 0; + + return percentDone; + } else if (Types.is(event, HttpResponse)) { + return parseAsset(event.body); + } else { + throw 'Invalid'; + } + }), + catchError((error: any) => { + if (Types.is(error, HttpErrorResponse) && error.status === 413) { + return throwError(new ErrorDto(413, 'Asset is too big.')); + } else { + return throwError(error); + } + }), + tap(value => { + if (!Types.isNumber(value)) { + this.analytics.trackEvent('Asset', 'Uploaded', appName); + } + }), + pretifyError('Failed to upload asset. Please reload.')); } public getAsset(appName: string, id: string): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}`); return HTTP.getVersioned(this.http, url).pipe( - map(({ payload }) => { - const body = payload.body; + map(({ payload }) => { + const body = payload.body; - return parseAsset(body); - }), - pretifyError('Failed to load assets. Please reload.')); + return parseAsset(body); + }), + pretifyError('Failed to load assets. Please reload.')); } public replaceFile(appName: string, asset: Resource, file: File, version: Version): Observable { @@ -201,33 +201,33 @@ export class AssetsService { const req = new HttpRequest(link.method, url, getFormData(file), { headers: new HttpHeaders().set('If-Match', version.value), reportProgress: true }); return this.http.request(req).pipe( - filter(event => - event.type === HttpEventType.UploadProgress || - event.type === HttpEventType.Response), - map(event => { - if (event.type === HttpEventType.UploadProgress) { - const percentDone = event.total ? Math.round(100 * event.loaded / event.total) : 0; - - return percentDone; - } else if (Types.is(event, HttpResponse)) { - return parseAsset(event.body); - } else { - throw 'Invalid'; - } - }), - catchError(error => { - if (Types.is(error, HttpErrorResponse) && error.status === 413) { - return throwError(new ErrorDto(413, 'Asset is too big.')); - } else { - return throwError(error); - } - }), - tap(value => { - if (!Types.isNumber(value)) { - this.analytics.trackEvent('Analytics', 'Replaced', appName); - } - }), - pretifyError('Failed to replace asset. Please reload.')); + filter(event => + event.type === HttpEventType.UploadProgress || + event.type === HttpEventType.Response), + map(event => { + if (event.type === HttpEventType.UploadProgress) { + const percentDone = event.total ? Math.round(100 * event.loaded / event.total) : 0; + + return percentDone; + } else if (Types.is(event, HttpResponse)) { + return parseAsset(event.body); + } else { + throw 'Invalid'; + } + }), + catchError(error => { + if (Types.is(error, HttpErrorResponse) && error.status === 413) { + return throwError(new ErrorDto(413, 'Asset is too big.')); + } else { + return throwError(error); + } + }), + tap(value => { + if (!Types.isNumber(value)) { + this.analytics.trackEvent('Analytics', 'Replaced', appName); + } + }), + pretifyError('Failed to replace asset. Please reload.')); } public putAsset(appName: string, asset: Resource, dto: AnnotateAssetDto, version: Version): Observable { @@ -236,13 +236,13 @@ export class AssetsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe( - map(({ payload }) => { - return parseAsset(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Analytics', 'Updated', appName); - }), - pretifyError('Failed to update asset. Please reload.')); + map(({ payload }) => { + return parseAsset(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Analytics', 'Updated', appName); + }), + pretifyError('Failed to update asset. Please reload.')); } public deleteAsset(appName: string, asset: Resource, version: Version): Observable> { @@ -251,10 +251,10 @@ export class AssetsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version).pipe( - tap(() => { - this.analytics.trackEvent('Analytics', 'Deleted', appName); - }), - pretifyError('Failed to delete asset. Please reload.')); + tap(() => { + this.analytics.trackEvent('Analytics', 'Deleted', appName); + }), + pretifyError('Failed to delete asset. Please reload.')); } } diff --git a/src/Squidex/app/shared/services/auth.service.ts b/src/Squidex/app/shared/services/auth.service.ts index d168850a4..ea05e730a 100644 --- a/src/Squidex/app/shared/services/auth.service.ts +++ b/src/Squidex/app/shared/services/auth.service.ts @@ -75,15 +75,15 @@ export class AuthService { Log.logger = console; this.userManager = new UserManager({ - client_id: 'squidex-frontend', - scope: 'squidex-api openid profile email squidex-profile role permissions', - response_type: 'id_token token', - redirect_uri: apiUrl.buildUrl('login;'), - post_logout_redirect_uri: apiUrl.buildUrl('logout'), - silent_redirect_uri: apiUrl.buildUrl('client-callback-silent'), - popup_redirect_uri: apiUrl.buildUrl('client-callback-popup'), - authority: apiUrl.buildUrl('identity-server/'), - userStore: new WebStorageStateStore({ store: window.localStorage || window.sessionStorage }), + client_id: 'squidex-frontend', + scope: 'squidex-api openid profile email squidex-profile role permissions', + response_type: 'id_token token', + redirect_uri: apiUrl.buildUrl('login;'), + post_logout_redirect_uri: apiUrl.buildUrl('logout'), + silent_redirect_uri: apiUrl.buildUrl('client-callback-silent'), + popup_redirect_uri: apiUrl.buildUrl('client-callback-popup'), + authority: apiUrl.buildUrl('identity-server/'), + userStore: new WebStorageStateStore({ store: window.localStorage || window.sessionStorage }), automaticSilentRenew: true }); @@ -103,7 +103,7 @@ export class AuthService { } public logoutRedirect() { - this.userManager.signoutRedirect(); + this.userManager.signoutRedirect(); } public loginRedirect() { diff --git a/src/Squidex/app/shared/services/backups.service.ts b/src/Squidex/app/shared/services/backups.service.ts index 492290d84..3af49a2c7 100644 --- a/src/Squidex/app/shared/services/backups.service.ts +++ b/src/Squidex/app/shared/services/backups.service.ts @@ -85,51 +85,51 @@ 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(item => parseBackup(item)); + map(({ items, _links }) => { + const backups = items.map(item => parseBackup(item)); - return new BackupsDto(backups, _links); - }), - pretifyError('Failed to load backups.')); + return new BackupsDto(backups, _links); + }), + pretifyError('Failed to load backups.')); } public getRestore(): Observable { const url = this.apiUrl.buildUrl(`api/apps/restore`); return this.http.get(url).pipe( - map(body => { - const restore = parseRestore(body); - - return restore; - }), - catchError(error => { - if (Types.is(error, HttpErrorResponse) && error.status === 404) { - return of(null); - } else { - return throwError(error); - } - }), - pretifyError('Failed to load backups.')); + map(body => { + const restore = parseRestore(body); + + return restore; + }), + catchError(error => { + if (Types.is(error, HttpErrorResponse) && error.status === 404) { + return of(null); + } else { + return throwError(error); + } + }), + pretifyError('Failed to load backups.')); } public postBackup(appName: string): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/backups`); return this.http.post(url, {}).pipe( - tap(() => { - this.analytics.trackEvent('Backup', 'Started', appName); - }), - pretifyError('Failed to start backup.')); + tap(() => { + this.analytics.trackEvent('Backup', 'Started', appName); + }), + pretifyError('Failed to start backup.')); } public postRestore(dto: StartRestoreDto): Observable { const url = this.apiUrl.buildUrl(`api/apps/restore`); return this.http.post(url, dto).pipe( - tap(() => { - this.analytics.trackEvent('Restore', 'Started'); - }), - pretifyError('Failed to start restore.')); + tap(() => { + this.analytics.trackEvent('Restore', 'Started'); + }), + pretifyError('Failed to start restore.')); } public deleteBackup(appName: string, resource: Resource): Observable { @@ -138,10 +138,10 @@ export class BackupsService { const url = this.apiUrl.buildUrl(link.href); return this.http.request(link.method, url).pipe( - tap(() => { - this.analytics.trackEvent('Backup', 'Deleted', appName); - }), - pretifyError('Failed to delete backup.')); + tap(() => { + this.analytics.trackEvent('Backup', 'Deleted', appName); + }), + pretifyError('Failed to delete backup.')); } } diff --git a/src/Squidex/app/shared/services/clients.service.ts b/src/Squidex/app/shared/services/clients.service.ts index 8bb895877..39a0473c2 100644 --- a/src/Squidex/app/shared/services/clients.service.ts +++ b/src/Squidex/app/shared/services/clients.service.ts @@ -80,23 +80,23 @@ export class ClientsService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients`); return HTTP.getVersioned(this.http, url).pipe( - mapVersioned(({ body }) => { - return parseClients(body); - }), - pretifyError('Failed to load clients. Please reload.')); + mapVersioned(({ body }) => { + return parseClients(body); + }), + pretifyError('Failed to load clients. Please reload.')); } public postClient(appName: string, dto: CreateClientDto, version: Version): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/clients`); return HTTP.postVersioned(this.http, url, dto, version).pipe( - mapVersioned(({ body }) => { - return parseClients(body); - }), - tap(() => { - this.analytics.trackEvent('Client', 'Created', appName); - }), - pretifyError('Failed to add client. Please reload.')); + mapVersioned(({ body }) => { + return parseClients(body); + }), + tap(() => { + this.analytics.trackEvent('Client', 'Created', appName); + }), + pretifyError('Failed to add client. Please reload.')); } public putClient(appName: string, resource: Resource, dto: UpdateClientDto, version: Version): Observable { @@ -105,13 +105,13 @@ export class ClientsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe( - mapVersioned(({ body }) => { - return parseClients(body); - }), - tap(() => { - this.analytics.trackEvent('Client', 'Updated', appName); - }), - pretifyError('Failed to revoke client. Please reload.')); + mapVersioned(({ body }) => { + return parseClients(body); + }), + tap(() => { + this.analytics.trackEvent('Client', 'Updated', appName); + }), + pretifyError('Failed to revoke client. Please reload.')); } public deleteClient(appName: string, resource: Resource, version: Version): Observable { @@ -120,13 +120,13 @@ export class ClientsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version).pipe( - mapVersioned(({ body }) => { - return parseClients(body); - }), - tap(() => { - this.analytics.trackEvent('Client', 'Deleted', appName); - }), - pretifyError('Failed to revoke client. Please reload.')); + mapVersioned(({ body }) => { + return parseClients(body); + }), + tap(() => { + this.analytics.trackEvent('Client', 'Deleted', appName); + }), + pretifyError('Failed to revoke client. Please reload.')); } public createToken(appName: string, client: ClientDto): Observable { @@ -141,10 +141,10 @@ export class ClientsService { const url = this.apiUrl.buildUrl('identity-server/connect/token'); return this.http.post(url, body, options).pipe( - map((response: any) => { - return new AccessTokenDto(response.access_token, response.token_type); - }), - pretifyError('Failed to create token. Please retry.')); + map((response: any) => { + return new AccessTokenDto(response.access_token, response.token_type); + }), + pretifyError('Failed to create token. Please retry.')); } } diff --git a/src/Squidex/app/shared/services/comments.service.ts b/src/Squidex/app/shared/services/comments.service.ts index 36694e8da..6fb4d4ba5 100644 --- a/src/Squidex/app/shared/services/comments.service.ts +++ b/src/Squidex/app/shared/services/comments.service.ts @@ -56,58 +56,58 @@ export class CommentsService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/comments/${commentsId}?version=${version.value}`); return this.http.get(url).pipe( - map(body => { - const comments = new CommentsDto( - body.createdComments.map((item: any) => { - return new CommentDto( - item.id, - DateTime.parseISO_UTC(item.time), - item.text, - item.user); - }), - body.updatedComments.map((item: any) => { - return new CommentDto( - item.id, - DateTime.parseISO_UTC(item.time), - item.text, - item.user); - }), - body.deletedComments, - new Version(body.version) - ); - - return comments; - }), - pretifyError('Failed to load comments.')); + map(body => { + const comments = new CommentsDto( + body.createdComments.map((item: any) => { + return new CommentDto( + item.id, + DateTime.parseISO_UTC(item.time), + item.text, + item.user); + }), + body.updatedComments.map((item: any) => { + return new CommentDto( + item.id, + DateTime.parseISO_UTC(item.time), + item.text, + item.user); + }), + body.deletedComments, + new Version(body.version) + ); + + return comments; + }), + pretifyError('Failed to load comments.')); } public postComment(appName: string, commentsId: string, dto: UpsertCommentDto): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/comments/${commentsId}`); return this.http.post(url, dto).pipe( - map(body => { - const comment = new CommentDto( - body.id, - DateTime.parseISO_UTC(body.time), - body.text, - body.user); - - return comment; - }), - pretifyError('Failed to create comment.')); + map(body => { + const comment = new CommentDto( + body.id, + DateTime.parseISO_UTC(body.time), + body.text, + body.user); + + return comment; + }), + pretifyError('Failed to create comment.')); } public putComment(appName: string, commentsId: string, commentId: string, dto: UpsertCommentDto): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/comments/${commentsId}/${commentId}`); return this.http.put(url, dto).pipe( - pretifyError('Failed to update comment.')); + pretifyError('Failed to update comment.')); } public deleteComment(appName: string, commentsId: string, commentId: string): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/comments/${commentsId}/${commentId}`); return this.http.delete(url).pipe( - pretifyError('Failed to delete comment.')); + pretifyError('Failed to delete comment.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/contents.service.ts b/src/Squidex/app/shared/services/contents.service.ts index bed10aeca..1096e3679 100644 --- a/src/Squidex/app/shared/services/contents.service.ts +++ b/src/Squidex/app/shared/services/contents.service.ts @@ -137,45 +137,45 @@ export class ContentsService { const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?${fullQuery}`); return this.http.get<{ total: number, items: [], statuses: StatusInfo[] } & Resource>(url).pipe( - map(({ total, items, statuses, _links }) => { - const contents = items.map(x => parseContent(x)); + map(({ total, items, statuses, _links }) => { + const contents = items.map(x => parseContent(x)); - return new ContentsDto(statuses, total, contents, _links); - }), - pretifyError('Failed to load contents. Please reload.')); + return new ContentsDto(statuses, total, contents, _links); + }), + pretifyError('Failed to load contents. Please reload.')); } public getContent(appName: string, schemaName: string, id: string): Observable { const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`); return HTTP.getVersioned(this.http, url).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - pretifyError('Failed to load content. Please reload.')); + map(({ payload }) => { + return parseContent(payload.body); + }), + pretifyError('Failed to load content. Please reload.')); } public getVersionData(appName: string, schemaName: string, id: string, version: Version): Observable> { const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/${version.value}`); return HTTP.getVersioned(this.http, url).pipe( - mapVersioned(({ body }) => { - return body; - }), - pretifyError('Failed to load data. Please reload.')); + mapVersioned(({ body }) => { + return body; + }), + pretifyError('Failed to load data. Please reload.')); } public postContent(appName: string, schemaName: string, dto: any, publish: boolean): Observable { const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?publish=${publish}`); return HTTP.postVersioned(this.http, url, dto).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Content', 'Created', appName); - }), - pretifyError('Failed to create content. Please reload.')); + map(({ payload }) => { + return parseContent(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Content', 'Created', appName); + }), + pretifyError('Failed to create content. Please reload.')); } public putContent(appName: string, resource: Resource, dto: any, version: Version): Observable { @@ -184,13 +184,13 @@ export class ContentsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.putVersioned(this.http, url, dto, version).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Content', 'Updated', appName); - }), - pretifyError('Failed to update content. Please reload.')); + map(({ payload }) => { + return parseContent(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Content', 'Updated', appName); + }), + pretifyError('Failed to update content. Please reload.')); } public patchContent(appName: string, resource: Resource, dto: any, version: Version): Observable { @@ -199,13 +199,13 @@ export class ContentsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Content', 'Updated', appName); - }), - pretifyError('Failed to update content. Please reload.')); + map(({ payload }) => { + return parseContent(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Content', 'Updated', appName); + }), + pretifyError('Failed to update content. Please reload.')); } public discardDraft(appName: string, resource: Resource, version: Version): Observable { @@ -214,13 +214,13 @@ export class ContentsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, {}).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Content', 'Discarded', appName); - }), - pretifyError('Failed to discard draft. Please reload.')); + map(({ payload }) => { + return parseContent(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Content', 'Discarded', appName); + }), + pretifyError('Failed to discard draft. Please reload.')); } public proposeDraft(appName: string, resource: Resource, dto: any, version: Version): Observable { @@ -229,13 +229,13 @@ export class ContentsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.putVersioned(this.http, url, dto, version).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Content', 'Updated', appName); - }), - pretifyError('Failed to propose draft. Please reload.')); + map(({ payload }) => { + return parseContent(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Content', 'Updated', appName); + }), + pretifyError('Failed to propose draft. Please reload.')); } public publishDraft(appName: string, resource: Resource, dueTime: string | null, version: Version): Observable { @@ -244,13 +244,13 @@ export class ContentsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, { status: 'Published', dueTime }).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Content', 'Discarded', appName); - }), - pretifyError('Failed to publish draft. Please reload.')); + map(({ payload }) => { + return parseContent(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Content', 'Discarded', appName); + }), + pretifyError('Failed to publish draft. Please reload.')); } public putStatus(appName: string, resource: Resource, status: string, dueTime: string | null, version: Version): Observable { @@ -259,13 +259,13 @@ export class ContentsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, { status, dueTime }).pipe( - map(({ payload }) => { - return parseContent(payload.body); - }), - tap(() => { - this.analytics.trackEvent('Content', 'Archived', appName); - }), - pretifyError(`Failed to ${status} content. Please reload.`)); + map(({ payload }) => { + return parseContent(payload.body); + }), + tap(() => { + this.analytics.trackEvent('Content', 'Archived', appName); + }), + pretifyError(`Failed to ${status} content. Please reload.`)); } public deleteContent(appName: string, resource: Resource, version: Version): Observable> { @@ -274,10 +274,10 @@ export class ContentsService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version).pipe( - tap(() => { - this.analytics.trackEvent('Content', 'Deleted', appName); - }), - pretifyError('Failed to delete content. Please reload.')); + tap(() => { + this.analytics.trackEvent('Content', 'Deleted', appName); + }), + pretifyError('Failed to delete content. Please reload.')); } } diff --git a/src/Squidex/app/shared/services/contributors.service.ts b/src/Squidex/app/shared/services/contributors.service.ts index a7cdeac72..452116a9b 100644 --- a/src/Squidex/app/shared/services/contributors.service.ts +++ b/src/Squidex/app/shared/services/contributors.service.ts @@ -50,7 +50,7 @@ export class ContributorDto { } } -export interface AssignContributorDto { +export interface AssignContributorDto { readonly contributorId: string; readonly role: string; readonly invite?: boolean; @@ -69,10 +69,10 @@ export class ContributorsService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/contributors`); return HTTP.getVersioned(this.http, url).pipe( - mapVersioned(({ body }) => { - return parseContributors(body); - }), - pretifyError('Failed to load contributors. Please reload.')); + mapVersioned(({ body }) => { + return parseContributors(body); + }), + pretifyError('Failed to load contributors. Please reload.')); } public postContributor(appName: string, dto: AssignContributorDto, version: Version): Observable { @@ -80,12 +80,12 @@ export class ContributorsService { return HTTP.postVersioned(this.http, url, dto, version).pipe( mapVersioned(({ body }) => { - return parseContributors(body); - }), - tap(() => { - this.analytics.trackEvent('Contributor', 'Configured', appName); - }), - pretifyError('Failed to add contributors. Please reload.')); + return parseContributors(body); + }), + tap(() => { + this.analytics.trackEvent('Contributor', 'Configured', appName); + }), + pretifyError('Failed to add contributors. Please reload.')); } public deleteContributor(appName: string, resource: Resource, version: Version): Observable { @@ -94,15 +94,15 @@ 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; - - return parseContributors(body); - }), - tap(() => { - this.analytics.trackEvent('Contributor', 'Deleted', appName); - }), - pretifyError('Failed to delete contributors. Please reload.')); + mapVersioned(payload => { + const body = payload.body; + + return parseContributors(body); + }), + tap(() => { + this.analytics.trackEvent('Contributor', 'Deleted', appName); + }), + pretifyError('Failed to delete contributors. Please reload.')); } } diff --git a/src/Squidex/app/shared/services/graphql.service.spec.ts b/src/Squidex/app/shared/services/graphql.service.spec.ts index 4221f51a9..d90390351 100644 --- a/src/Squidex/app/shared/services/graphql.service.spec.ts +++ b/src/Squidex/app/shared/services/graphql.service.spec.ts @@ -32,7 +32,7 @@ describe('GraphQlService', () => { let graphQlResult: any = null; - graphQlService.query('my-app', { }).subscribe(result => { + graphQlService.query('my-app', {}).subscribe(result => { graphQlResult = result; }); diff --git a/src/Squidex/app/shared/services/help.service.ts b/src/Squidex/app/shared/services/help.service.ts index b37528fd7..7abb21adf 100644 --- a/src/Squidex/app/shared/services/help.service.ts +++ b/src/Squidex/app/shared/services/help.service.ts @@ -21,6 +21,6 @@ export class HelpService { const url = `https://raw.githubusercontent.com/Squidex/squidex-docs/master/${helpPage}.md`; return this.http.get(url, { responseType: 'text' }).pipe( - catchError(() => of(''))); + catchError(() => of(''))); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/history.service.ts b/src/Squidex/app/shared/services/history.service.ts index d79add475..95fef8ede 100644 --- a/src/Squidex/app/shared/services/history.service.ts +++ b/src/Squidex/app/shared/services/history.service.ts @@ -82,17 +82,17 @@ export class HistoryService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/history?channel=${channel}`); return this.http.get(url).pipe( - map(body => { - const history = body.map(item => - new HistoryEventDto( - item.eventId, - item.actor, - item.message, - item.version, - DateTime.parseISO_UTC(item.created))); - - return history; - }), - pretifyError('Failed to load history. Please reload.')); + map(body => { + const history = body.map(item => + new HistoryEventDto( + item.eventId, + item.actor, + item.message, + item.version, + DateTime.parseISO_UTC(item.created))); + + return history; + }), + pretifyError('Failed to load history. Please reload.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/languages.service.ts b/src/Squidex/app/shared/services/languages.service.ts index ea76d2936..d905f63e2 100644 --- a/src/Squidex/app/shared/services/languages.service.ts +++ b/src/Squidex/app/shared/services/languages.service.ts @@ -32,14 +32,14 @@ export class LanguagesService { const url = this.apiUrl.buildUrl('api/languages'); return this.http.get(url).pipe( - map(body => { - const languages = body.map(item => - new LanguageDto( - item.iso2Code, - item.englishName)); + map(body => { + const languages = body.map(item => + new LanguageDto( + item.iso2Code, + item.englishName)); - return languages; - }), - pretifyError('Failed to load languages. Please reload.')); + return languages; + }), + pretifyError('Failed to load languages. Please reload.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/news.service.ts b/src/Squidex/app/shared/services/news.service.ts index db7e02a5f..2c3be90fc 100644 --- a/src/Squidex/app/shared/services/news.service.ts +++ b/src/Squidex/app/shared/services/news.service.ts @@ -40,19 +40,19 @@ export class NewsService { const url = this.apiUrl.buildUrl(`api/news/features?version=${version}`); return this.http.get(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; - }), - pretifyError('Failed to load features. Please reload.')); + map(body => { + const items: any[] = body.features; + + const features = new FeaturesDto( + items.map(item => + new FeatureDto( + item.name, + item.text) + ), + body.version); + + return features; + }), + pretifyError('Failed to load features. Please reload.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/plans.service.ts b/src/Squidex/app/shared/services/plans.service.ts index 31e1ace9a..6410cc22a 100644 --- a/src/Squidex/app/shared/services/plans.service.ts +++ b/src/Squidex/app/shared/services/plans.service.ts @@ -62,42 +62,42 @@ export class PlansService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/plans`); return HTTP.getVersioned(this.http, url).pipe( - mapVersioned(({ body }) => { - const items: any[] = body.plans; + mapVersioned(({ body }) => { + const items: any[] = body.plans; - const { hasPortal, currentPlanId, planOwner } = body; + const { hasPortal, currentPlanId, planOwner } = body; - const plans = { - currentPlanId, - planOwner, - plans: items.map(item => - new PlanDto( - item.id, - item.name, - item.costs, - item.yearlyId, - item.yearlyCosts, - item.maxApiCalls, - item.maxAssetSize, - item.maxContributors)), - hasPortal - }; + const plans = { + currentPlanId, + planOwner, + plans: items.map(item => + new PlanDto( + item.id, + item.name, + item.costs, + item.yearlyId, + item.yearlyCosts, + item.maxApiCalls, + item.maxAssetSize, + item.maxContributors)), + hasPortal + }; - return plans; - }), - pretifyError('Failed to load plans. Please reload.')); + return plans; + }), + pretifyError('Failed to load plans. Please reload.')); } public putPlan(appName: string, dto: ChangePlanDto, version: Version): Observable> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/plan`); return HTTP.putVersioned(this.http, url, dto, version).pipe( - mapVersioned(payload => { - return payload.body; - }), - tap(() => { - this.analytics.trackEvent('Plan', 'Changed', appName); - }), - pretifyError('Failed to change plan. Please reload.')); + mapVersioned(payload => { + return payload.body; + }), + tap(() => { + this.analytics.trackEvent('Plan', 'Changed', appName); + }), + pretifyError('Failed to change plan. Please reload.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/roles.service.ts b/src/Squidex/app/shared/services/roles.service.ts index 7fa11d194..bc5a72154 100644 --- a/src/Squidex/app/shared/services/roles.service.ts +++ b/src/Squidex/app/shared/services/roles.service.ts @@ -72,23 +72,23 @@ export class RolesService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/roles`); return HTTP.getVersioned(this.http, url).pipe( - mapVersioned(({ body }) => { - return parseRoles(body); - }), - pretifyError('Failed to load roles. Please reload.')); + mapVersioned(({ body }) => { + return parseRoles(body); + }), + pretifyError('Failed to load roles. Please reload.')); } public postRole(appName: string, dto: CreateRoleDto, version: Version): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/roles`); return HTTP.postVersioned(this.http, url, dto, version).pipe( - mapVersioned(({ body }) => { - return parseRoles(body); - }), - tap(() => { - this.analytics.trackEvent('Role', 'Created', appName); - }), - pretifyError('Failed to add role. Please reload.')); + mapVersioned(({ body }) => { + return parseRoles(body); + }), + tap(() => { + this.analytics.trackEvent('Role', 'Created', appName); + }), + pretifyError('Failed to add role. Please reload.')); } public putRole(appName: string, resource: Resource, dto: UpdateRoleDto, version: Version): Observable { @@ -97,13 +97,13 @@ export class RolesService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe( - mapVersioned(({ body }) => { - return parseRoles(body); - }), - tap(() => { - this.analytics.trackEvent('Role', 'Updated', appName); - }), - pretifyError('Failed to revoke role. Please reload.')); + mapVersioned(({ body }) => { + return parseRoles(body); + }), + tap(() => { + this.analytics.trackEvent('Role', 'Updated', appName); + }), + pretifyError('Failed to revoke role. Please reload.')); } public deleteRole(appName: string, resource: Resource, version: Version): Observable { @@ -112,20 +112,20 @@ export class RolesService { const url = this.apiUrl.buildUrl(link.href); return HTTP.requestVersioned(this.http, link.method, url, version).pipe( - mapVersioned(({ body }) => { - return parseRoles(body); - }), - tap(() => { - this.analytics.trackEvent('Role', 'Deleted', appName); - }), - pretifyError('Failed to revoke role. Please reload.')); + mapVersioned(({ body }) => { + return parseRoles(body); + }), + tap(() => { + this.analytics.trackEvent('Role', 'Deleted', appName); + }), + pretifyError('Failed to revoke role. Please reload.')); } public getPermissions(appName: string): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/roles/permissions`); return this.http.get(url).pipe( - pretifyError('Failed to load permissions. Please reload.')); + pretifyError('Failed to load permissions. Please reload.')); } } diff --git a/src/Squidex/app/shared/services/rules.service.ts b/src/Squidex/app/shared/services/rules.service.ts index 5c42f7dec..b4f6c8350 100644 --- a/src/Squidex/app/shared/services/rules.service.ts +++ b/src/Squidex/app/shared/services/rules.service.ts @@ -41,7 +41,8 @@ export const ALL_TRIGGERS = { description: 'When a schema definition has been created, updated, published or deleted...', display: 'Schema changed', iconColor: '#3389ff', - iconCode: 'schemas'}, + iconCode: 'schemas' + }, 'Usage': { description: 'When monthly API calls exceed a specified limit for one time a month...', display: 'Usage exceeded', diff --git a/src/Squidex/app/shared/services/translations.service.ts b/src/Squidex/app/shared/services/translations.service.ts index b5b91897d..30d8ee52b 100644 --- a/src/Squidex/app/shared/services/translations.service.ts +++ b/src/Squidex/app/shared/services/translations.service.ts @@ -38,9 +38,9 @@ export class TranslationsService { const url = this.apiUrl.buildUrl(`api/apps/${appName}/translations`); return this.http.post(url, request).pipe( - map(body => { - return new TranslationDto(body.result, body.text); - }), - pretifyError('Failed to translate text. Please reload.')); + map(body => { + return new TranslationDto(body.result, body.text); + }), + pretifyError('Failed to translate text. Please reload.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/ui.service.ts b/src/Squidex/app/shared/services/ui.service.ts index 13b23b28d..cdadc29a1 100644 --- a/src/Squidex/app/shared/services/ui.service.ts +++ b/src/Squidex/app/shared/services/ui.service.ts @@ -41,7 +41,7 @@ export class UIService { return this.http.get(url).pipe( catchError(() => { - return of({ }); + return of({}); })); } diff --git a/src/Squidex/app/shared/services/usages.service.ts b/src/Squidex/app/shared/services/usages.service.ts index dbd004aae..e97b99106 100644 --- a/src/Squidex/app/shared/services/usages.service.ts +++ b/src/Squidex/app/shared/services/usages.service.ts @@ -72,55 +72,55 @@ export class UsagesService { const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/calls/month`); return this.http.get(url).pipe( - map(body => { - return new CurrentCallsDto(body.count, body.maxAllowed); - }), - pretifyError('Failed to load monthly api calls. Please reload.')); + map(body => { + return new CurrentCallsDto(body.count, body.maxAllowed); + }), + pretifyError('Failed to load monthly api calls. Please reload.')); } public getTodayStorage(app: string): Observable { const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/storage/today`); return this.http.get(url).pipe( - map(body => { - return new CurrentStorageDto(body.size, body.maxAllowed); - }), - pretifyError('Failed to load todays storage size. Please reload.')); + map(body => { + return new CurrentStorageDto(body.size, body.maxAllowed); + }), + pretifyError('Failed to load todays storage size. Please reload.')); } public getCallsUsages(app: string, fromDate: DateTime, toDate: DateTime): Observable<{ [category: string]: CallsUsageDto[] }> { const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/calls/${fromDate.toUTCStringFormat('YYYY-MM-DD')}/${toDate.toUTCStringFormat('YYYY-MM-DD')}`); return this.http.get(url).pipe( - map(body => { - const usages: { [category: string]: CallsUsageDto[] } = {}; - - for (let category of Object.keys(body)) { - usages[category] = body[category].map((item: any) => - new CallsUsageDto( - DateTime.parseISO_UTC(item.date), - item.count, - item.averageMs)); - } - - return usages; - }), - pretifyError('Failed to load calls usage. Please reload.')); + map(body => { + const usages: { [category: string]: CallsUsageDto[] } = {}; + + for (let category of Object.keys(body)) { + usages[category] = body[category].map((item: any) => + new CallsUsageDto( + DateTime.parseISO_UTC(item.date), + item.count, + item.averageMs)); + } + + return usages; + }), + pretifyError('Failed to load calls usage. Please reload.')); } public getStorageUsages(app: string, fromDate: DateTime, toDate: DateTime): Observable { const url = this.apiUrl.buildUrl(`api/apps/${app}/usages/storage/${fromDate.toUTCStringFormat('YYYY-MM-DD')}/${toDate.toUTCStringFormat('YYYY-MM-DD')}`); return this.http.get(url).pipe( - map(body => { - const usages = body.map(item => - new StorageUsageDto( - DateTime.parseISO_UTC(item.date), - item.count, - item.size)); + map(body => { + const usages = body.map(item => + new StorageUsageDto( + DateTime.parseISO_UTC(item.date), + item.count, + item.size)); - return usages; - }), - pretifyError('Failed to load storage usage. Please reload.')); + return usages; + }), + pretifyError('Failed to load storage usage. Please reload.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/users.service.ts b/src/Squidex/app/shared/services/users.service.ts index 6f4d4c1da..7c245db05 100644 --- a/src/Squidex/app/shared/services/users.service.ts +++ b/src/Squidex/app/shared/services/users.service.ts @@ -44,38 +44,38 @@ export class UsersService { const url = this.apiUrl.buildUrl(`api/users?query=${query || ''}`); return this.http.get(url).pipe( - map(body => { - const users = body.map(item => - new UserDto( - item.id, - item.displayName)); + map(body => { + const users = body.map(item => + new UserDto( + item.id, + item.displayName)); - return users; - }), - pretifyError('Failed to load users. Please reload.')); + return users; + }), + pretifyError('Failed to load users. Please reload.')); } public getUser(id: string): Observable { const url = this.apiUrl.buildUrl(`api/users/${id}`); return this.http.get(url).pipe( - map(body => { - const user = new UserDto( - body.id, - body.displayName); + map(body => { + const user = new UserDto( + body.id, + body.displayName); - return user; - }), - pretifyError('Failed to load user. Please reload.')); + return user; + }), + pretifyError('Failed to load user. Please reload.')); } public getResources(): Observable { const url = this.apiUrl.buildUrl(`api`); return this.http.get<{ _links: {} }>(url).pipe( - map(({ _links }) => { - return new ResourcesDto(_links); - }), - pretifyError('Failed to load user. Please reload.')); + map(({ _links }) => { + return new ResourcesDto(_links); + }), + pretifyError('Failed to load user. Please reload.')); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/workflows.service.spec.ts b/src/Squidex/app/shared/services/workflows.service.spec.ts new file mode 100644 index 000000000..cdf96ce7f --- /dev/null +++ b/src/Squidex/app/shared/services/workflows.service.spec.ts @@ -0,0 +1,436 @@ +/* + * 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 { + AnalyticsService, + ApiUrlConfig, + Resource, + Version, + Versioned, + WorkflowDto, + WorkflowPayload, + WorkflowsService +} from '@app/shared/internal'; + +describe('WorkflowsService', () => { + + const version = new Version('1'); + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule + ], + providers: [ + WorkflowsService, + { provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') }, + { provide: AnalyticsService, useValue: new AnalyticsService() } + ] + }); + }); + + afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => { + httpMock.verify(); + })); + + it('should make a get request to get app workflows', + inject([WorkflowsService, HttpTestingController], (workflowsService: WorkflowsService, httpMock: HttpTestingController) => { + + let workflow: Versioned; + + workflowsService.getWorkflow('my-app').subscribe(result => { + workflow = result; + }); + + const req = httpMock.expectOne('http://service/p/api/apps/my-app/workflow'); + + expect(req.request.method).toEqual('GET'); + expect(req.request.headers.get('If-Match')).toBeNull(); + + req.flush(workflowsResponse('Draft'), + { + headers: { + etag: '2' + } + }); + + expect(workflow!).toEqual({ payload: createWorkflow('Draft'), version: new Version('2') }); + })); + + it('should make a put request to assign a workflow', + inject([WorkflowsService, HttpTestingController], (workflowsService: WorkflowsService, httpMock: HttpTestingController) => { + + const resource: Resource = { + _links: { + update: { method: 'PUT', href: '/api/apps/my-app/workflow' } + } + }; + + let workflow: Versioned; + + workflowsService.putWorkflow('my-app', resource, {}, version).subscribe(result => { + workflow = result; + }); + + const req = httpMock.expectOne('http://service/p/api/apps/my-app/workflow'); + + expect(req.request.method).toEqual('PUT'); + expect(req.request.headers.get('If-Match')).toEqual(version.value); + + req.flush(workflowsResponse('Draft'), { + headers: { + etag: '2' + } + }); + + expect(workflow!).toEqual({ payload: createWorkflow('Draft'), version: new Version('2') }); + })); + + function workflowsResponse(name: string) { + return { + workflow: { + steps: { + [`${name}1`]: { + transitions: { + [`${name}2`]: { + expression: 'Expression1', role: 'Role1' + } + }, + color: `${name}1`, noUpdate: true + }, + [`${name}2`]: { + transitions: { + [`${name}1`]: { + expression: 'Expression2', role: 'Role2' + } + }, + color: `${name}2`, noUpdate: true + } + }, + initial: `${name}1`, + _links: { + update: { method: 'PUT', href: '/api/workflows' } + } + }, + _links: {}, + canCreate: true + }; + } +}); + +export function createWorkflow(name: string): WorkflowPayload { + return { + workflow: new WorkflowDto({ + update: { method: 'PUT', href: '/api/workflows' } + }, + `${name}1`, + [ + { name: `${name}1`, color: `${name}1`, noUpdate: true, isLocked: false }, + { name: `${name}2`, color: `${name}2`, noUpdate: true, isLocked: false } + ], + [ + { from: `${name}1`, to: `${name}2`, expression: 'Expression1', role: 'Role1' }, + { from: `${name}2`, to: `${name}1`, expression: 'Expression2', role: 'Role2' } + ]), + _links: {} + }; +} + +describe('Workflow', () => { + it('should create empty workflow', () => { + const workflow = new WorkflowDto(); + + expect(workflow.initial); + }); + + it('should add step to workflow', () => { + const workflow = + new WorkflowDto() + .setStep('1', { color: '#00ff00' }); + + expect(workflow.serialize()).toEqual({ + steps: { + '1': { transitions: {}, color: '#00ff00' } + }, + initial: '1' + }); + }); + + it('should override settings if step already exists', () => { + const workflow = + new WorkflowDto() + .setStep('1', { color: '#00ff00', noUpdate: true }) + .setStep('1', { color: 'red' }); + + expect(workflow.serialize()).toEqual({ + steps: { + '1': { transitions: {}, color: 'red', noUpdate: true } + }, + initial: '1' + }); + }); + + it('should return same workflow if step to update is locked', () => { + const workflow = + new WorkflowDto() + .setStep('1', { color: '#00ff00', isLocked: true }); + + const updated = workflow.setStep('1', { color: 'red' }); + + expect(updated).toBe(workflow); + }); + + it('should sort steps case invariant', () => { + const workflow = + new WorkflowDto() + .setStep('Z') + .setStep('a'); + + expect(workflow.steps).toEqual([ + { name: 'a' }, + { name: 'Z' } + ]); + }); + + it('should return same workflow if step to remove is locked', () => { + const workflow = + new WorkflowDto() + .setStep('1', { color: '#00ff00', isLocked: true }); + + const updated = workflow.removeStep('1'); + + expect(updated).toBe(workflow); + }); + + it('should return same workflow if step to remove not found', () => { + const workflow = + new WorkflowDto() + .setStep('1'); + + const updated = workflow.removeStep('3'); + + expect(updated).toBe(workflow); + }); + + it('should remove step', () => { + const workflow = + new WorkflowDto() + .setStep('1', { color: '#00ff00' }) + .setStep('2', { color: '#ff0000' }) + .setStep('3', { color: '#0000ff' }) + .setTransition('1', '2', { expression: '1 === 2' }) + .setTransition('1', '3', { expression: '1 === 3' }) + .setTransition('2', '3', { expression: '2 === 3' }) + .removeStep('1'); + + expect(workflow.serialize()).toEqual({ + steps: { + '2': { + transitions: { + '3': { expression: '2 === 3' } + }, + color: '#ff0000' + }, + '3': { transitions: {}, color: '#0000ff' } + }, + initial: '2' + }); + }); + + it('should make first non-locked step the initial step if initial removed', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2', { isLocked: true }) + .setStep('3') + .removeStep('1'); + + expect(workflow.serialize()).toEqual({ + steps: { + '2': { transitions: {}, isLocked: true }, + '3': { transitions: {} } + }, + initial: '3' + }); + }); + + it('should unset initial step if initial removed', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .removeStep('1'); + + expect(workflow.serialize()).toEqual({ steps: {}, initial: undefined }); + }); + + it('should rename step', () => { + const workflow = + new WorkflowDto() + .setStep('1', { color: '#00ff00' }) + .setStep('2', { color: '#ff0000' }) + .setStep('3', { color: '#0000ff' }) + .setTransition('1', '2', { expression: '1 === 2' }) + .setTransition('2', '1', { expression: '2 === 1' }) + .setTransition('2', '3', { expression: '2 === 3' }) + .renameStep('1', 'a'); + + expect(workflow.serialize()).toEqual({ + steps: { + 'a': { + transitions: { + '2': { expression: '1 === 2' } + }, + color: '#00ff00' + }, + '2': { + transitions: { + 'a': { expression: '2 === 1' }, + '3': { expression: '2 === 3' } + }, + color: '#ff0000' + }, + '3': { transitions: {}, color: '#0000ff' } + }, + initial: 'a' + }); + }); + + it('should add transitions to workflow', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2') + .setTransition('1', '2', { expression: '1 === 2' }) + .setTransition('2', '1', { expression: '2 === 1' }); + + expect(workflow.serialize()).toEqual({ + steps: { + '1': { + transitions: { + '2': { expression: '1 === 2' } + } + }, + '2': { + transitions: { + '1': { expression: '2 === 1' } + } + } + }, + initial: '1' + }); + }); + + it('should remove transition from workflow', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2') + .setTransition('1', '2', { expression: '1 === 2' }) + .setTransition('2', '1', { expression: '2 === 1' }) + .removeTransition('1', '2'); + + expect(workflow.serialize()).toEqual({ + steps: { + '1': { transitions: {}}, + '2': { + transitions: { + '1': { expression: '2 === 1' } + } + } + }, + initial: '1' + }); + }); + + it('should override settings if transition already exists', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2') + .setTransition('2', '1', { expression: '2 === 1', role: 'Role' }) + .setTransition('2', '1', { expression: '2 !== 1' }); + + expect(workflow.serialize()).toEqual({ + steps: { + '1': { transitions: {} }, + '2': { + transitions: { + '1': { expression: '2 !== 1', role: 'Role' } + } + } + }, + initial: '1' + }); + }); + + it('should return same workflow if transition to update not found by from step', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2') + .setTransition('1', '2'); + + const updated = workflow.setTransition('3', '2', { role: 'Role' }); + + expect(updated).toBe(workflow); + }); + + it('should return same workflow if transition to update not found by to step', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2') + .setTransition('1', '2'); + + const updated = workflow.setTransition('1', '3', { role: 'Role' }); + + expect(updated).toBe(workflow); + }); + + it('should return same workflow if transition to remove not', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2') + .setTransition('1', '2'); + + const updated = workflow.removeTransition('1', '3'); + + expect(updated).toBe(workflow); + }); + + it('should return same workflow if step to make initial is locked', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2', { color: '#00ff00', isLocked: true }); + + const updated = workflow.setInitial('2'); + + expect(updated).toBe(workflow); + }); + + it('should set initial step', () => { + const workflow = + new WorkflowDto() + .setStep('1') + .setStep('2') + .setInitial('2'); + + expect(workflow.serialize()).toEqual({ + steps: { + '1': { transitions: {} }, + '2': { transitions: {} } + }, + initial: '2' + }); + }); + +}); \ No newline at end of file diff --git a/src/Squidex/app/shared/services/workflows.service.ts b/src/Squidex/app/shared/services/workflows.service.ts new file mode 100644 index 000000000..ce9861f10 --- /dev/null +++ b/src/Squidex/app/shared/services/workflows.service.ts @@ -0,0 +1,294 @@ +/* + * 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 { tap } from 'rxjs/operators'; + +import { + AnalyticsService, + ApiUrlConfig, + compareStringsAsc, + hasAnyLink, + HTTP, + mapVersioned, + pretifyError, + Resource, + ResourceLinks, + Version, + Versioned +} from '@app/framework'; + +export type WorkflowsDto = Versioned; +export type WorkflowPayload = { workflow: WorkflowDto; } & Resource; + +export class WorkflowDto { + public readonly _links: ResourceLinks; + + public readonly canUpdate: boolean; + + public static DEFAULT = + new WorkflowDto() + .setStep('Draft', { color: '#8091a5' }) + .setStep('Archived', { color: '#eb3142', noUpdate: true }) + .setStep('Published', { color: '#4bb958', isLocked: true }) + .setTransition('Archived', 'Draft') + .setTransition('Draft', 'Archived') + .setTransition('Draft', 'Published') + .setTransition('Published', 'Draft') + .setTransition('Published', 'Archived'); + + constructor(links: ResourceLinks = {}, + public readonly initial?: string, + public readonly steps: WorkflowStep[] = [], + private readonly transitions: WorkflowTransition[] = [] + ) { + this.steps.sort((a, b) => compareStringsAsc(a.name, b.name)); + + this.transitions.sort((a, b) => compareStringsAsc(a.to, b.to)); + + this._links = links; + + this.canUpdate = hasAnyLink(links, 'update'); + } + + public getOpenSteps(step: WorkflowStep) { + return this.steps.filter(x => x.name !== step.name && !this.transitions.find(y => y.from === step.name && y.to === x.name)); + } + + public getTransitions(step: WorkflowStep): WorkflowTransitionView[] { + return this.transitions.filter(x => x.from === step.name).map(x => ({ step: this.getStep(x.to), ...x })); + } + + public getStep(name: string): WorkflowStep { + return this.steps.find(x => x.name === name)!; + } + + public setStep(name: string, values: Partial = {}) { + const found = this.getStep(name); + + if (found) { + const { name: _, ...existing } = found; + + if (found.isLocked) { + return this; + } + + values = { ...existing, ...values }; + } + + const steps = [...this.steps.filter(s => s !== found), { name, ...values }]; + + let initial = this.initial; + + if (steps.length === 1) { + initial = steps[0].name; + } + + return new WorkflowDto(this._links, initial, steps, this.transitions); + } + + public setInitial(initial: string) { + const found = this.getStep(initial); + + if (!found || found.isLocked) { + return this; + } + + return new WorkflowDto(this._links, initial, this.steps, this.transitions); + } + + public removeStep(name: string) { + const steps = this.steps.filter(s => s.name !== name || s.isLocked); + + if (steps.length === this.steps.length) { + return this; + } + + const transitions = + steps.length !== this.steps.length ? + this.transitions.filter(t => t.from !== name && t.to !== name) : + this.transitions; + + let initial = this.initial; + + if (initial === name) { + const first = steps.find(x => !x.isLocked); + + initial = first ? first.name : undefined; + } + + return new WorkflowDto(this._links, initial, steps, transitions); + } + + public renameStep(name: string, newName: string) { + const steps = this.steps.map(step => { + if (step.name === name) { + return { ...step, name: newName }; + } + + return step; + }); + + const transitions = this.transitions.map(transition => { + if (transition.from === name || transition.to === name) { + let newTransition = { ...transition }; + + if (newTransition.from === name) { + newTransition.from = newName; + } + + if (newTransition.to === name) { + newTransition.to = newName; + } + + return newTransition; + } + + return transition; + }); + + let initial = this.initial; + + if (initial === name) { + initial = newName; + } + + return new WorkflowDto(this._links, initial, steps, transitions); + } + + public removeTransition(from: string, to: string) { + const transitions = this.transitions.filter(t => t.from !== from || t.to !== to); + + if (transitions.length === this.transitions.length) { + return this; + } + + return new WorkflowDto(this._links, this.initial, this.steps, transitions); + } + + public setTransition(from: string, to: string, values: Partial = {}) { + const stepFrom = this.getStep(from); + + if (!stepFrom) { + return this; + } + + const stepTo = this.getStep(to); + + if (!stepTo) { + return this; + } + + const found = this.transitions.find(x => x.from === from && x.to === to); + + if (found) { + const { from: _, to: __, ...existing } = found; + + values = { ...existing, ...values }; + } + + const transitions = [...this.transitions.filter(t => t !== found), { from, to, ...values }]; + + return new WorkflowDto(this._links, this.initial, this.steps, transitions); + } + + public serialize(): any { + const result = { steps: {}, initial: this.initial }; + + for (let step of this.steps) { + const { name, ...values } = step; + + const s = { ...values, transitions: {} }; + + for (let transition of this.getTransitions(step)) { + const { from, to, step: _, ...t } = transition; + + s.transitions[to] = t; + } + + result.steps[name] = s; + } + + return result; + } +} + +export type WorkflowStepValues = { color?: string; isLocked?: boolean; noUpdate?: boolean; }; +export type WorkflowStep = { name: string } & WorkflowStepValues; + +export type WorkflowTransitionValues = { expression?: string; role?: string; }; +export type WorkflowTransition = { from: string; to: string } & WorkflowTransitionValues; + +export type WorkflowTransitionView = { step: WorkflowStep } & WorkflowTransition; + +@Injectable() +export class WorkflowsService { + constructor( + private readonly http: HttpClient, + private readonly apiUrl: ApiUrlConfig, + private readonly analytics: AnalyticsService + ) { + } + + public getWorkflow(appName: string): Observable> { + const url = this.apiUrl.buildUrl(`api/apps/${appName}/workflow`); + + return HTTP.getVersioned(this.http, url).pipe( + mapVersioned(({ body }) => { + return parseWorkflowPayload(body); + }), + pretifyError('Failed to load workflows. Please reload.')); + } + + public putWorkflow(appName: string, resource: Resource, dto: any, version: Version): Observable> { + const link = resource._links['update']; + + const url = this.apiUrl.buildUrl(link.href); + + return HTTP.requestVersioned(this.http, link.method, url, version, dto).pipe( + mapVersioned(({ body }) => { + return parseWorkflowPayload(body); + }), + tap(() => { + this.analytics.trackEvent('Workflow', 'Configured', appName); + }), + pretifyError('Failed to configure Workflow. Please reload.')); + } +} + +function parseWorkflowPayload(response: any) { + const { workflow, _links } = response; + + const result = parseWorkflow(workflow); + + return { workflow: result, _links }; +} + +function parseWorkflow(workflow: any) { + const steps: WorkflowStep[] = []; + const transitions: WorkflowTransition[] = []; + + for (let stepName in workflow.steps) { + if (workflow.steps.hasOwnProperty(stepName)) { + const step = workflow.steps[stepName]; + + steps.push({ name: stepName, color: step.color, noUpdate: step.noUpdate, isLocked: stepName === 'Published' }); + + for (let to in step.transitions) { + if (step.transitions.hasOwnProperty(to)) { + const transition = step.transitions[to]; + + transitions.push({ from: stepName, to, ...transition }); + } + } + } + } + + return new WorkflowDto(workflow._links, workflow.initial, steps, transitions); +} \ No newline at end of file diff --git a/src/Squidex/app/shared/state/asset-uploader.state.ts b/src/Squidex/app/shared/state/asset-uploader.state.ts index 4b16ade66..5280b2d26 100644 --- a/src/Squidex/app/shared/state/asset-uploader.state.ts +++ b/src/Squidex/app/shared/state/asset-uploader.state.ts @@ -43,7 +43,7 @@ interface Snapshot { uploads: UploadList; } -export class UploadCanceled { } +export class UploadCanceled {} type UploadList = ImmutableArray; type UploadResult = AssetDto | number; diff --git a/src/Squidex/app/shared/state/workflows.state.spec.ts b/src/Squidex/app/shared/state/workflows.state.spec.ts new file mode 100644 index 000000000..4ad671a27 --- /dev/null +++ b/src/Squidex/app/shared/state/workflows.state.spec.ts @@ -0,0 +1,102 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { of } from 'rxjs'; +import { IMock, It, Mock, Times } from 'typemoq'; + +import { + DialogService, + versioned, + WorkflowPayload, + WorkflowsService, + WorkflowsState +} from '@app/shared/internal'; + +import { createWorkflow } from '../services/workflows.service.spec'; + +import { TestValues } from './_test-helpers'; + +describe('WorkflowsState', () => { + const { + app, + appsState, + newVersion, + version + } = TestValues; + + const oldWorkflow = createWorkflow('test'); + + let dialogs: IMock; + let workflowsService: IMock; + let workflowsState: WorkflowsState; + + beforeEach(() => { + dialogs = Mock.ofType(); + + workflowsService = Mock.ofType(); + workflowsState = new WorkflowsState(workflowsService.object, appsState.object, dialogs.object); + }); + + afterEach(() => { + workflowsService.verifyAll(); + }); + + describe('Loading', () => { + it('should load workflow', () => { + workflowsService.setup(x => x.getWorkflow(app)) + .returns(() => of(versioned(version, oldWorkflow))).verifiable(); + + workflowsState.load().subscribe(); + + expect(workflowsState.snapshot.workflow).toEqual(oldWorkflow.workflow); + expect(workflowsState.snapshot.isLoaded).toBeTruthy(); + expect(workflowsState.snapshot.version).toEqual(version); + + dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.never()); + }); + + it('should show notification on load when reload is true', () => { + workflowsService.setup(x => x.getWorkflow(app)) + .returns(() => of(versioned(version, oldWorkflow))).verifiable(); + + workflowsState.load(true).subscribe(); + + expect().nothing(); + + dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.once()); + }); + }); + + describe('Updates', () => { + beforeEach(() => { + workflowsService.setup(x => x.getWorkflow(app)) + .returns(() => of(versioned(version, oldWorkflow))).verifiable(); + + workflowsState.load().subscribe(); + }); + + it('should update workflows when saved', () => { + const updated = createWorkflow('updated'); + + const request = oldWorkflow.workflow.serialize(); + + workflowsService.setup(x => x.putWorkflow(app, oldWorkflow.workflow, request, version)) + .returns(() => of(versioned(newVersion, updated))).verifiable(); + + workflowsState.save(oldWorkflow.workflow).subscribe(); + + expectNewWorkflows(updated); + + dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.once()); + }); + + function expectNewWorkflows(updated: WorkflowPayload) { + expect(workflowsState.snapshot.workflow).toEqual(updated.workflow); + expect(workflowsState.snapshot.version).toEqual(newVersion); + } + }); +}); \ No newline at end of file diff --git a/src/Squidex/app/shared/state/workflows.state.ts b/src/Squidex/app/shared/state/workflows.state.ts new file mode 100644 index 000000000..b43a558e0 --- /dev/null +++ b/src/Squidex/app/shared/state/workflows.state.ts @@ -0,0 +1,98 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +// tslint:disable: no-shadowed-variable + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +import { + DialogService, + shareMapSubscribed, + shareSubscribed, + State, + Version +} from '@app/framework'; + +import { AppsState } from './apps.state'; + +import { + WorkflowDto, + WorkflowPayload, + WorkflowsService +} from './../services/workflows.service'; + +interface Snapshot { + // The current workflow. + workflow?: WorkflowDto; + + // The app version. + version: Version; + + // Indicates if the workflows are loaded. + isLoaded?: boolean; +} + +@Injectable() +export class WorkflowsState extends State { + public workflow = + this.project(x => x.workflow); + + public isLoaded = + this.project(x => !!x.isLoaded); + + constructor( + private readonly workflowsService: WorkflowsService, + private readonly appsState: AppsState, + private readonly dialogs: DialogService + ) { + super({ version: Version.EMPTY }); + } + + public load(isReload = false): Observable { + if (!isReload) { + this.resetState(); + } + + return this.workflowsService.getWorkflow(this.appName).pipe( + tap(({ version, payload }) => { + if (isReload) { + this.dialogs.notifyInfo('Workflow reloaded.'); + } + + this.replaceWorkflow(payload, version); + }), + shareMapSubscribed(this.dialogs, x => x.payload.workflow)); + } + + public save(workflow: WorkflowDto): Observable { + return this.workflowsService.putWorkflow(this.appName, workflow, workflow.serialize(), this.version).pipe( + tap(({ version, payload }) => { + this.replaceWorkflow(payload, version); + + this.dialogs.notifyInfo('Workflow has been saved.'); + }), + shareSubscribed(this.dialogs)); + } + + private replaceWorkflow(payload: WorkflowPayload, version: Version) { + const { workflow } = payload; + + this.next(s => { + return { ...s, workflow, isLoaded: true, version }; + }); + } + + private get appName() { + return this.appsState.appName; + } + + private get version() { + return this.snapshot.version; + } +} \ No newline at end of file diff --git a/src/Squidex/app/shared/utils/messages.ts b/src/Squidex/app/shared/utils/messages.ts index 3716abc49..0e0696eb8 100644 --- a/src/Squidex/app/shared/utils/messages.ts +++ b/src/Squidex/app/shared/utils/messages.ts @@ -5,4 +5,4 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -export class HistoryChannelUpdated { } \ No newline at end of file +export class HistoryChannelUpdated {} \ No newline at end of file diff --git a/src/Squidex/app/theme/_panels.scss b/src/Squidex/app/theme/_panels.scss index e8f35e99e..e97323d77 100644 --- a/src/Squidex/app/theme/_panels.scss +++ b/src/Squidex/app/theme/_panels.scss @@ -96,6 +96,10 @@ border: 0; } + &-blank-bordered { + border-top: 1px solid $color-border; + } + // Scrolling must be enabled optionally to prevent bugs. &-scroll { overflow-y: scroll; diff --git a/src/Squidex/app/theme/icomoon/demo.html b/src/Squidex/app/theme/icomoon/demo.html index d4ac2ada2..b6cb4ccfc 100644 --- a/src/Squidex/app/theme/icomoon/demo.html +++ b/src/Squidex/app/theme/icomoon/demo.html @@ -9,11 +9,238 @@
-

Font Name: icomoon (Glyphs: 122)

+

Font Name: icomoon (Glyphs: 123)

-

Grid Size: Unknown

+

Grid Size: 24

+
+
+ + + + icon-corner-down-right +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-info-outline +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-upload-2 +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-translate +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-arrow_back +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-external-link +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-minus-square +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-plus-square +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-drag2 +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-comments +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-backup +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-support +
+
+ + +
+
+ liga: + +
+
+
+
+ + + + icon-control-RichText +
+
+ + +
+
+ liga: + +
+
+
+ + + + icon-download +
+
+ + +
+
+ liga: + +
+
+
+
+

Grid Size: Unknown

+
@@ -29,7 +256,7 @@
-
+
@@ -45,7 +272,7 @@
-
+
@@ -61,7 +288,7 @@
-
+
@@ -77,7 +304,7 @@
-
+
@@ -93,7 +320,7 @@
-
+
@@ -109,7 +336,7 @@
-
+
@@ -125,7 +352,7 @@
-
+
@@ -141,7 +368,7 @@
-
+
@@ -157,7 +384,7 @@
-
+
@@ -173,7 +400,7 @@
-
+
@@ -189,7 +416,7 @@
-
+
@@ -205,7 +432,7 @@
-
+
@@ -221,7 +448,7 @@
-
+
@@ -237,7 +464,7 @@
-
+
@@ -253,7 +480,7 @@
-
+
@@ -269,7 +496,7 @@
-
+
@@ -285,7 +512,7 @@
-
+
@@ -301,7 +528,7 @@
-
+
@@ -317,7 +544,7 @@
-
+
@@ -333,7 +560,7 @@
-
+
@@ -349,7 +576,7 @@
-
+
@@ -365,7 +592,7 @@
-
+
@@ -381,7 +608,7 @@
-
+
@@ -397,7 +624,7 @@
-
+
@@ -413,7 +640,7 @@
-
+
@@ -429,7 +656,7 @@
-
+
@@ -445,7 +672,7 @@
-
+
@@ -461,7 +688,7 @@
-
+
@@ -477,7 +704,7 @@
-
+
@@ -493,7 +720,7 @@
-
+
@@ -509,7 +736,7 @@
-
+
@@ -525,7 +752,7 @@
-
+
@@ -541,7 +768,7 @@
-
+
@@ -557,7 +784,7 @@
-
+
@@ -573,7 +800,7 @@
-
+
-
+
@@ -605,7 +832,7 @@
-
+
@@ -621,7 +848,7 @@
-
+
@@ -637,7 +864,7 @@
-
+
@@ -653,7 +880,7 @@
-
+
@@ -669,7 +896,7 @@
-
+
@@ -685,7 +912,7 @@
-
+
@@ -701,7 +928,7 @@
-
+
@@ -717,7 +944,7 @@
-
+
@@ -733,7 +960,7 @@
-
+
@@ -749,7 +976,7 @@
-
+
@@ -765,7 +992,7 @@
-
+
@@ -781,7 +1008,7 @@
-
+
@@ -797,7 +1024,7 @@
-
+
@@ -813,7 +1040,7 @@
-
+
@@ -829,7 +1056,7 @@
-
+
@@ -845,7 +1072,7 @@
-
+
@@ -861,7 +1088,7 @@
-
+
@@ -877,7 +1104,7 @@
-
+
@@ -894,217 +1121,6 @@
-
-

Grid Size: 24

-
-
- - - - icon-info-outline -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-upload-2 -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-translate -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-arrow_back -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-external-link -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-minus-square -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-plus-square -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-drag2 -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-comments -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-backup -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-support -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-control-RichText -
-
- - -
-
- liga: - -
-
-
-
- - - - icon-download -
-
- - -
-
- liga: - -
-
-

Grid Size: 16

diff --git a/src/Squidex/app/theme/icomoon/fonts/icomoon.eot b/src/Squidex/app/theme/icomoon/fonts/icomoon.eot index d6b54da7c..31e82fd0b 100644 Binary files a/src/Squidex/app/theme/icomoon/fonts/icomoon.eot and b/src/Squidex/app/theme/icomoon/fonts/icomoon.eot differ diff --git a/src/Squidex/app/theme/icomoon/fonts/icomoon.svg b/src/Squidex/app/theme/icomoon/fonts/icomoon.svg index 187add00b..8c6023c3b 100644 --- a/src/Squidex/app/theme/icomoon/fonts/icomoon.svg +++ b/src/Squidex/app/theme/icomoon/fonts/icomoon.svg @@ -126,6 +126,7 @@ + diff --git a/src/Squidex/app/theme/icomoon/fonts/icomoon.ttf b/src/Squidex/app/theme/icomoon/fonts/icomoon.ttf index 59451f61e..0a90d59a4 100644 Binary files a/src/Squidex/app/theme/icomoon/fonts/icomoon.ttf and b/src/Squidex/app/theme/icomoon/fonts/icomoon.ttf differ diff --git a/src/Squidex/app/theme/icomoon/fonts/icomoon.woff b/src/Squidex/app/theme/icomoon/fonts/icomoon.woff index 4427657d9..e25d9d1c6 100644 Binary files a/src/Squidex/app/theme/icomoon/fonts/icomoon.woff and b/src/Squidex/app/theme/icomoon/fonts/icomoon.woff differ diff --git a/src/Squidex/app/theme/icomoon/selection.json b/src/Squidex/app/theme/icomoon/selection.json index b1e634a08..2ce2b6bdc 100644 --- a/src/Squidex/app/theme/icomoon/selection.json +++ b/src/Squidex/app/theme/icomoon/selection.json @@ -1 +1 @@ -{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M512 682.667h-341.333c-5.845 0-11.349-1.152-16.299-3.2-5.205-2.133-9.899-5.333-13.867-9.301s-7.125-8.661-9.301-13.867c-2.048-4.949-3.2-10.453-3.2-16.299v-426.667c0-5.845 1.152-11.349 3.2-16.299 2.133-5.205 5.333-9.899 9.301-13.867s8.661-7.125 13.867-9.301c4.949-2.048 10.453-3.2 16.299-3.2h682.667c5.845 0 11.349 1.152 16.299 3.2 5.205 2.133 9.899 5.333 13.867 9.301s7.125 8.661 9.301 13.867c2.048 4.949 3.2 10.453 3.2 16.299v426.667c0 5.845-1.152 11.349-3.2 16.299-2.133 5.205-5.333 9.899-9.301 13.867s-8.661 7.125-13.867 9.301c-4.949 2.048-10.453 3.2-16.299 3.2zM469.333 768v85.333h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-85.333h298.667c17.28 0 33.835-3.456 48.981-9.728 15.701-6.485 29.781-16 41.557-27.776s21.291-25.856 27.776-41.557c6.229-15.104 9.685-31.659 9.685-48.939v-426.667c0-17.28-3.456-33.835-9.728-48.981-6.485-15.701-16-29.781-27.776-41.557s-25.856-21.291-41.557-27.776c-15.104-6.229-31.659-9.685-48.939-9.685h-682.667c-17.28 0-33.835 3.456-48.981 9.728-15.659 6.485-29.739 16-41.515 27.776s-21.291 25.856-27.776 41.515c-6.272 15.147-9.728 31.701-9.728 48.981v426.667c0 17.28 3.456 33.835 9.728 48.981 6.485 15.701 16 29.781 27.776 41.557s25.856 21.291 41.557 27.776c15.104 6.229 31.659 9.685 48.939 9.685z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["monitor"],"grid":0},"attrs":[{}],"properties":{"order":132,"id":0,"prevSize":24,"code":59765,"name":"type-UI"},"setIdx":0,"setId":5,"iconIdx":0},{"icon":{"paths":["M66.337 575.491l276.668-171.531v-57.177l-331.627 207.614v42.189l331.627 207.614-0-57.177z","M957.663 575.49l-276.668-171.531v-57.177l331.627 207.614v42.189l-331.627 207.614 0-57.177z","M583.295 214.183l-200.825 621.623 53.007 17.527 200.837-621.623z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["prerender"],"grid":0},"attrs":[{},{},{}],"properties":{"order":114,"id":0,"name":"prerender","prevSize":24,"code":59724},"setIdx":4,"setId":1,"iconIdx":38},{"icon":{"paths":["M1024 512c0 282.77-229.23 512-512 512s-512-229.23-512-512c0-282.77 229.23-512 512-512s512 229.23 512 512z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["circle"],"grid":0},"attrs":[{}],"properties":{"order":106,"id":1,"name":"circle","prevSize":24,"code":59729},"setIdx":4,"setId":1,"iconIdx":39},{"icon":{"paths":["M512 0c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h128v870.4h-128c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h307.2c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6h-128v-870.4h128c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6h-307.2zM51.2 204.8c-28.16 0-51.2 23.040-51.2 51.2v460.8c0 28.16 23.040 51.2 51.2 51.2h537.6v-51.2h-512c-15.36 0-25.6-10.24-25.6-25.6v-409.6c0-15.36 10.24-25.6 25.6-25.6h512v-51.2h-537.6zM742.4 204.8v51.2h204.8c15.36 0 25.6 10.24 25.6 25.6v409.6c0 15.36-10.24 25.6-25.6 25.6h-204.8v51.2h230.4c28.16 0 51.2-23.040 51.2-51.2v-460.8c0-28.16-23.040-51.2-51.2-51.2h-230.4z","M386.56 606.72c0 12.8-7.68 23.040-20.48 25.6-28.16 10.24-58.88 15.36-92.16 15.36-35.84 0-66.56-10.24-84.48-25.6s-25.6-38.4-25.6-66.56 10.24-51.2 25.6-66.56c17.92-17.92 46.080-23.040 84.48-23.040h69.12v-38.4c0-35.84-25.6-53.76-64-53.76-23.040 0-46.080 7.68-69.12 20.48-2.56 2.56-5.12 2.56-10.24 2.56-10.24 0-20.48-7.68-20.48-20.48 0-7.68 2.56-12.8 10.24-17.92 30.72-20.48 61.44-25.6 92.16-25.6 56.32 0 104.96 30.72 104.96 92.16v181.76zM345.6 501.76h-69.12c-61.44 0-69.12 28.16-69.12 53.76s7.68 56.32 69.12 56.32c23.040 0 46.080-2.56 69.12-10.24v-99.84z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Slug"],"grid":0},"attrs":[{},{}],"properties":{"order":103,"id":2,"name":"control-Slug","prevSize":24,"code":59727},"setIdx":4,"setId":1,"iconIdx":40},{"icon":{"paths":["M295.954 822.751h-94.705c-47.353 0-88.786-41.434-88.786-88.786v-491.283c0-47.353 41.434-88.786 88.786-88.786h94.705v-59.191h-94.705c-82.867 0-147.977 65.11-147.977 147.977v491.283c0 82.867 65.11 147.977 147.977 147.977h94.705v-59.191z","M970.728 473.526c-82.867-171.653-201.249-378.821-272.277-378.821h-112.462v59.191h112.462c35.514 11.838 136.139 177.572 213.087 337.387-76.948 153.896-177.572 325.549-213.087 337.387h-112.462v59.191h112.462c71.029 0 183.491-207.168 272.277-384.74l5.919-11.838-5.919-17.757z","M266.358 337.341v260.462h59.191v-260.462z","M479.422 337.341v260.462h59.191v-260.462z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["Tags"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":98,"id":3,"name":"type-Tags","prevSize":24,"code":59722},"setIdx":4,"setId":1,"iconIdx":41},{"icon":{"paths":["M512 102.4c-200.4 0-366.954 144.072-402.4 334.2-0.031 0.165-0.069 0.335-0.1 0.5-2.974 16.061-4.76 32.441-5.8 49.1-0.017 0.271-0.084 0.529-0.1 0.8 0.019 0.004 0.080-0.004 0.1 0-0.503 8.31-1.3 16.564-1.3 25 0 226.202 183.398 409.6 409.6 409.6 208.165 0 379.707-155.44 405.8-356.5 0.004-0.033-0.004-0.067 0-0.1 1.94-14.978 3.124-30.16 3.4-45.6 0.044-2.487 0.4-4.903 0.4-7.4 0-226.202-183.398-409.6-409.6-409.6zM512 153.6c185.461 0 337.902 140.924 356.4 321.5-35.181-21.812-84.232-39.9-151.6-39.9-85.35 0-140.891 41.606-194.6 81.9-49.152 36.864-95.55 71.7-163.8 71.7-86.067 0-135.862-54.67-175.9-98.6-9.001-9.901-17.11-17.483-25.4-25.3 23.131-175.603 172.981-311.3 354.9-311.3zM716.8 486.4c77.828 0 125.173 28.221 152.2 52.8-13.96 185.173-168.254 331.2-357 331.2-190.097 0-345.175-148.14-357.2-335.2 41.826 45.372 102.577 104.8 203.6 104.8 85.35 0 140.891-41.606 194.6-81.9 49.152-36.915 95.55-71.7 163.8-71.7z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["activity"],"grid":0},"attrs":[{}],"properties":{"order":12,"id":4,"name":"activity, history, time","prevSize":24,"code":59652},"setIdx":4,"setId":1,"iconIdx":42},{"icon":{"paths":["M512 0c-35.392 0-64 28.608-64 64v384h-384c-35.392 0-64 28.608-64 64s28.608 64 64 64h384v384c0 35.392 28.608 64 64 64s64-28.608 64-64v-384h384c35.392 0 64-28.608 64-64s-28.608-64-64-64h-384v-384c0-35.392-28.608-64-64-64z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["add"],"grid":0},"attrs":[{}],"properties":{"order":13,"id":5,"name":"add, plus","prevSize":24,"code":59653},"setIdx":4,"setId":1,"iconIdx":43},{"icon":{"paths":["M512 102.4c-226.202 0-409.6 183.398-409.6 409.6s183.398 409.6 409.6 409.6c226.202 0 409.6-183.398 409.6-409.6s-183.398-409.6-409.6-409.6zM512 153.6c197.632 0 358.4 160.819 358.4 358.4s-160.768 358.4-358.4 358.4c-197.632 0-358.4-160.819-358.4-358.4s160.768-358.4 358.4-358.4zM691.9 333c-12.893 0.002-25.782 4.882-35.5 14.6l-222.2 221.9-67.7-67.5c-19.19-19.294-51.085-19.215-70.3 0-19.15 19.15-19.15 51.050 0 70.2 0.198 0.2 26.198 26.681 52 53 12.95 13.209 25.761 26.372 35.2 36 4.719 4.814 8.607 8.755 11.2 11.4 1.296 1.322 2.293 2.281 2.9 2.9 0.279 0.282 0.488 0.486 0.6 0.6 0.001 0.001 7.591-7.429 14.6-14.3l-14.5 14.4 0.2 0.2v0.1c19.43 19.327 51.57 19.327 71 0v-0.1l258.1-257.6c19.546-19.447 19.521-51.885-0.1-71.3-9.731-9.679-22.607-14.502-35.5-14.5z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["check-circle"],"grid":0},"attrs":[{}],"properties":{"order":14,"id":6,"name":"check-circle","prevSize":24,"code":59654},"setIdx":4,"setId":1,"iconIdx":44},{"icon":{"paths":["M512 1024c-282.778 0-512-229.222-512-512s229.222-512 512-512 512 229.222 512 512-229.222 512-512 512zM855.808 270.592c-19.2-19.2-50.278-19.2-69.478 0l-376.73 376.73-171.878-171.93c-19.2-19.2-50.278-19.2-69.478 0s-19.2 50.278 0 69.478c0 0 201.523 205.261 204.8 208.486 9.984 10.138 23.347 14.643 36.557 14.080 13.21 0.563 26.573-3.942 36.608-14.029 3.277-3.226 409.6-413.286 409.6-413.286 19.2-19.2 19.2-50.33 0-69.53z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["check-circle-filled"],"grid":0},"attrs":[{}],"properties":{"order":27,"id":7,"name":"check-circle-filled","prevSize":24,"code":59655},"setIdx":4,"setId":1,"iconIdx":45},{"icon":{"paths":["M601.024 512l276.736 276.736c24.512 24.576 24.512 64.384 0 89.024-24.64 24.576-64.384 24.576-89.024 0l-276.736-276.736-276.736 276.736c-24.512 24.576-64.384 24.576-89.024 0-24.512-24.64-24.512-64.448 0-89.024l276.736-276.736-276.736-276.736c-24.512-24.576-24.512-64.384 0-89.024 24.64-24.576 64.512-24.576 89.024 0l276.736 276.736 276.736-276.736c24.64-24.576 64.384-24.576 89.024 0 24.512 24.64 24.512 64.448 0 89.024l-276.736 276.736z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["close"],"grid":0},"attrs":[{}],"properties":{"order":28,"id":8,"name":"close","prevSize":24,"code":59656},"setIdx":4,"setId":1,"iconIdx":46},{"icon":{"paths":["M409.6 435.2h-153.6v51.2h153.6v-51.2zM409.6 332.8h-153.6v51.2h153.6v-51.2zM256 691.2h409.6v-51.2h-409.6v51.2zM409.6 230.4h-153.6v51.2h153.6v-51.2zM870.4 179.2h-51.2v-51.2c0-28.262-22.938-51.2-51.2-51.2h-614.4c-28.262 0-51.2 22.938-51.2 51.2v665.6c0 28.262 22.938 51.2 51.2 51.2h51.2v51.2c0 28.262 22.938 51.2 51.2 51.2h614.4c28.262 0 51.2-22.938 51.2-51.2v-665.6c0-28.262-22.938-51.2-51.2-51.2zM179.2 793.6c-14.157 0-25.6-11.443-25.6-25.6v-614.4c0-14.131 11.443-25.6 25.6-25.6h563.2c14.157 0 25.6 11.469 25.6 25.6v614.4c0 14.157-11.443 25.6-25.6 25.6h-563.2zM870.4 870.4c0 14.157-11.443 25.6-25.6 25.6h-563.2c-14.157 0-25.6-11.443-25.6-25.6v-25.6h512c28.262 0 51.2-22.938 51.2-51.2v-563.2h25.6c14.157 0 25.6 11.469 25.6 25.6v614.4zM614.4 230.4h-102.4c-28.262 0-51.2 22.938-51.2 51.2v153.6c0 28.262 22.938 51.2 51.2 51.2h102.4c28.262 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.938-51.2-51.2-51.2zM614.4 435.2h-102.4v-153.6h102.4v153.6zM256 588.8h409.6v-51.2h-409.6v51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["content"],"grid":0},"attrs":[{}],"properties":{"order":37,"id":9,"name":"type-References","prevSize":24,"code":59657},"setIdx":4,"setId":1,"iconIdx":47},{"icon":{"paths":["M793.6 844.8c0 14.157-11.443 25.6-25.6 25.6h-665.6c-14.131 0-25.6-11.443-25.6-25.6v-665.6c0-14.157 11.469-25.6 25.6-25.6h665.6c14.157 0 25.6 11.443 25.6 25.6v102.4h51.2v-128c0-28.262-22.938-51.2-51.2-51.2h-716.8c-28.262 0-51.2 22.938-51.2 51.2v716.8c0 28.262 22.938 51.2 51.2 51.2h716.8c28.262 0 51.2-22.938 51.2-51.2v-281.6h-51.2v256zM991.078 237.747c-9.958-9.958-26.035-9.958-35.968 0l-391.91 391.91-238.31-238.31c-9.958-9.958-26.061-9.958-35.942 0-9.958 9.907-9.958 26.010 0 35.942l254.874 254.874c0.461 0.538 0.614 1.203 1.126 1.69 5.043 5.018 11.674 7.475 18.278 7.373 6.605 0.102 13.235-2.355 18.278-7.373 0.512-0.512 0.666-1.178 1.126-1.69l408.448-408.474c9.933-9.933 9.933-26.035 0-35.942z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-checkbox"],"grid":0},"attrs":[{}],"properties":{"order":38,"id":10,"name":"control-Checkbox","prevSize":24,"code":59658},"setIdx":4,"setId":1,"iconIdx":48},{"icon":{"paths":["M51.2 0c-28.262 0-51.2 22.938-51.2 51.2v281.6c0 28.262 22.938 51.2 51.2 51.2h921.6c28.262 0 51.2-22.938 51.2-51.2v-281.6c0-28.262-22.938-51.2-51.2-51.2h-921.6zM76.8 51.2h512v281.6h-512c-14.157 0-25.6-11.443-25.6-25.6v-230.4c0-14.157 11.443-25.6 25.6-25.6zM640 51.2h307.2c14.157 0 25.6 11.443 25.6 25.6v230.4c0 14.157-11.443 25.6-25.6 25.6h-307.2v-281.6zM716.8 153.6c-0.41 0.358 89.139 102.938 89.6 102.4 0.512 0 89.6-95.36 89.6-102.4 0 0.384-172.16 0-179.2 0zM128 435.2c-42.394 0-76.8 34.406-76.8 76.8s34.406 76.8 76.8 76.8c42.394 0 76.8-34.406 76.8-76.8s-34.406-76.8-76.8-76.8zM128 486.4c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6c-14.157 0-25.6-11.443-25.6-25.6s11.443-25.6 25.6-25.6zM307.2 486.4c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h640c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-640zM128 640c-42.394 0-76.8 34.381-76.8 76.8s34.406 76.8 76.8 76.8c42.394 0 76.8-34.381 76.8-76.8s-34.406-76.8-76.8-76.8zM128 691.2c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6c-14.157 0-25.6-11.443-25.6-25.6s11.443-25.6 25.6-25.6zM307.2 691.2c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h640c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-640zM128 844.8c-42.394 0-76.8 34.381-76.8 76.8s34.406 76.8 76.8 76.8c42.394 0 76.8-34.381 76.8-76.8s-34.406-76.8-76.8-76.8zM128 896c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6c-14.157 0-25.6-11.443-25.6-25.6s11.443-25.6 25.6-25.6zM307.2 896c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h640c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-640z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-dropdown"],"grid":0},"attrs":[{}],"properties":{"order":39,"id":11,"name":"control-Dropdown","prevSize":24,"code":59659},"setIdx":4,"setId":1,"iconIdx":49},{"icon":{"paths":["M512 0c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h128v870.4h-128c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h307.2c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-128v-870.4h128c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-307.2zM51.2 204.8c-28.262 0-51.2 22.938-51.2 51.2v460.8c0 28.262 22.938 51.2 51.2 51.2h537.6v-51.2h-512c-14.131 0-25.6-11.443-25.6-25.6v-409.6c0-14.157 11.469-25.6 25.6-25.6h512v-51.2h-537.6zM742.4 204.8v51.2h204.8c14.157 0 25.6 11.443 25.6 25.6v409.6c0 14.157-11.443 25.6-25.6 25.6h-204.8v51.2h230.4c28.262 0 51.2-22.938 51.2-51.2v-460.8c0-28.262-22.938-51.2-51.2-51.2h-230.4zM285.9 307c-0.589 0.051-1.161 0.048-1.75 0.15-8.243 0.051-16.396 4.474-20.85 13.050l-132.55 306.25c-6.656 12.749-2.866 28.981 8.5 36.2 11.341 7.219 25.97 2.749 32.6-10l27.65-63.85h170.5c0.512 0 0.914-0.224 1.4-0.25l27.45 64.050c6.63 12.749 21.136 17.269 32.4 10.050s15.005-23.451 8.4-36.2l-131.3-306.25c-4.454-8.576-12.432-12.973-20.65-13.050-0.614-0.102-1.211-0.099-1.8-0.15zM285.9 389.15l63.65 148.45h-127.9l64.25-148.45z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-input"],"grid":0},"attrs":[{}],"properties":{"order":41,"id":12,"name":"control-Input","prevSize":24,"code":59660},"setIdx":4,"setId":1,"iconIdx":50},{"icon":{"paths":["M153.6 716.8c-84.787 0-153.6 68.813-153.6 153.6s68.813 153.6 153.6 153.6c84.787 0 153.6-68.813 153.6-153.6s-68.813-153.6-153.6-153.6zM153.6 972.8c-56.55 0-102.4-45.85-102.4-102.4s45.85-102.4 102.4-102.4c56.55 0 102.4 45.85 102.4 102.4s-45.85 102.4-102.4 102.4zM384 179.2h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6zM998.4 486.4h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6zM153.6 0c-84.787 0-153.6 68.787-153.6 153.6s68.813 153.6 153.6 153.6c84.787 0 153.6-68.787 153.6-153.6s-68.813-153.6-153.6-153.6zM153.6 256c-56.55 0-102.4-45.85-102.4-102.4s45.85-102.4 102.4-102.4c56.55 0 102.4 45.85 102.4 102.4s-45.85 102.4-102.4 102.4zM153.6 358.4c-84.787 0-153.6 68.787-153.6 153.6 0 84.787 68.813 153.6 153.6 153.6s153.6-68.813 153.6-153.6c0-84.813-68.813-153.6-153.6-153.6zM153.6 614.4c-56.55 0-102.4-45.85-102.4-102.4s45.85-102.4 102.4-102.4c56.55 0 102.4 45.85 102.4 102.4s-45.85 102.4-102.4 102.4zM153.6 102.4c-28.262 0-51.2 22.938-51.2 51.2s22.938 51.2 51.2 51.2c28.262 0 51.2-22.938 51.2-51.2s-22.938-51.2-51.2-51.2zM998.4 844.8h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-radio"],"grid":0},"attrs":[{}],"properties":{"order":42,"id":13,"name":"control-Radio","prevSize":24,"code":59661},"setIdx":4,"setId":1,"iconIdx":51},{"icon":{"paths":["M0 0v204.8h76.8v76.8h51.2v-76.8h76.8v-204.8h-204.8zM819.2 0v204.8h204.8v-204.8h-204.8zM51.2 51.2h102.4v102.4h-102.4v-102.4zM870.4 51.2h102.4v102.4h-102.4v-102.4zM281.6 76.8v51.2h102.4v-51.2h-102.4zM486.4 76.8v51.2h102.4v-51.2h-102.4zM691.2 76.8v51.2h102.4v-51.2h-102.4zM333.25 204.8c-7.091-0.307-14.348 2.097-19.75 7.55l-74.75 74.75c-10.317 10.291-10.317 27.083 0 37.4s27.059 10.317 37.35 0l68.45-68.5h141.85v486.4h-50.7c-7.117-0.307-14.348 2.097-19.75 7.55l-23.6 23.55c-10.317 10.317-10.317 27.083 0 37.4 10.291 10.317 27.109 10.317 37.4 0l17.25-17.3h129.75l18.050 18c10.394 10.368 27.181 10.368 37.6 0 10.368-10.394 10.368-27.181 0-37.6l-24-24c-5.478-5.478-12.682-7.907-19.85-7.6h-50.95v-486.4h141.55l69.25 69.2c10.394 10.368 27.155 10.368 37.6 0 10.368-10.368 10.368-27.181 0-37.6l-75.2-75.2c-5.478-5.478-12.706-7.907-19.9-7.6h-357.65zM896 281.6v102.4h51.2v-102.4h-51.2zM76.8 384v102.4h51.2v-102.4h-51.2zM896 486.4v102.4h51.2v-102.4h-51.2zM76.8 588.8v102.4h51.2v-102.4h-51.2zM896 691.2v102.4h51.2v-102.4h-51.2zM76.8 793.6v25.6h-76.8v204.8h204.8v-76.8h76.8v-51.2h-76.8v-76.8h-76.8v-25.6h-51.2zM819.2 819.2v76.8h-25.6v51.2h25.6v76.8h204.8v-204.8h-204.8zM51.2 870.4h102.4v102.4h-102.4v-102.4zM870.4 870.4h102.4v102.4h-102.4v-102.4zM384 896v51.2h102.4v-51.2h-102.4zM588.8 896v51.2h102.4v-51.2h-102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-textarea"],"grid":0},"attrs":[{}],"properties":{"order":17,"id":14,"name":"control-TextArea","prevSize":24,"code":59662},"setIdx":4,"setId":1,"iconIdx":52},{"icon":{"paths":["M332.8 25.6c-127.258 0-230.4 103.142-230.4 230.4s103.142 230.4 230.4 230.4h358.4c127.258 0 230.4-103.142 230.4-230.4s-103.142-230.4-230.4-230.4h-358.4zM332.8 76.8h358.4c98.97 0 179.2 80.23 179.2 179.2s-80.23 179.2-179.2 179.2h-358.4c-98.97 0-179.2-80.23-179.2-179.2s80.23-179.2 179.2-179.2zM332.8 128c-70.707 0-128 57.293-128 128s57.293 128 128 128c70.707 0 128-57.293 128-128s-57.293-128-128-128zM332.8 179.2c42.419 0 76.8 34.381 76.8 76.8s-34.381 76.8-76.8 76.8c-42.419 0-76.8-34.381-76.8-76.8s34.381-76.8 76.8-76.8zM332.8 537.6c-127.258 0-230.4 103.142-230.4 230.4s103.142 230.4 230.4 230.4h358.4c127.258 0 230.4-103.142 230.4-230.4s-103.142-230.4-230.4-230.4h-358.4zM332.8 588.8h358.4c98.97 0 179.2 80.23 179.2 179.2s-80.23 179.2-179.2 179.2h-358.4c-98.97 0-179.2-80.23-179.2-179.2s80.23-179.2 179.2-179.2zM691.2 640c-70.707 0-128 57.293-128 128s57.293 128 128 128c70.707 0 128-57.293 128-128s-57.293-128-128-128zM691.2 691.2c42.419 0 76.8 34.381 76.8 76.8s-34.381 76.8-76.8 76.8c-42.419 0-76.8-34.381-76.8-76.8s34.381-76.8 76.8-76.8z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-toggle"],"grid":0},"attrs":[{}],"properties":{"order":16,"id":15,"name":"control-Toggle","prevSize":24,"code":59663},"setIdx":4,"setId":1,"iconIdx":53},{"icon":{"paths":["M204.8 51.2c-56.525 0-102.4 45.875-102.4 102.4v512c0 56.525 45.875 102.4 102.4 102.4h409.6c56.525 0 102.4-45.875 102.4-102.4v-512c0-56.525-45.875-102.4-102.4-102.4h-409.6zM204.8 102.4h409.6c28.262 0 51.2 22.886 51.2 51.2v512c0 28.314-22.938 51.2-51.2 51.2h-409.6c-28.262 0-51.2-22.886-51.2-51.2v-512c0-28.314 22.938-51.2 51.2-51.2zM768 204.8v51.2c28.262 0 51.2 22.886 51.2 51.2v512c0 28.314-22.938 51.2-51.2 51.2h-409.6c-28.262 0-51.2-22.886-51.2-51.2h-51.2c0 56.525 45.875 102.4 102.4 102.4h409.6c56.525 0 102.4-45.875 102.4-102.4v-512c0-56.525-45.875-102.4-102.4-102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["copy"],"grid":0},"attrs":[{}],"properties":{"order":90,"id":16,"name":"copy","prevSize":24,"code":59664},"setIdx":4,"setId":1,"iconIdx":54},{"icon":{"paths":["M828.8 1024h-633.6c-105.6 0-195.2-89.6-195.2-195.2v-320c0-281.6 227.2-508.8 505.6-508.8 288 0 518.4 230.4 518.4 518.4v310.4c0 105.6-89.6 195.2-195.2 195.2zM505.6 64c-243.2 0-441.6 198.4-441.6 441.6v320c0 73.6 60.8 134.4 131.2 134.4h630.4c73.6 0 131.2-60.8 131.2-131.2v-310.4c3.2-249.6-201.6-454.4-451.2-454.4z","M512 668.8c-3.2 0-6.4 0-6.4 0-32-3.2-64-19.2-80-48l-192-278.4c-9.6-9.6-9.6-25.6-0-38.4 9.6-9.6 25.6-12.8 38.4-6.4l294.4 172.8c28.8 16 48 44.8 51.2 76.8s-6.4 64-28.8 89.6c-19.2 22.4-48 32-76.8 32zM364.8 428.8l108.8 160c6.4 9.6 19.2 19.2 32 19.2s25.6-3.2 35.2-12.8c9.6-9.6 12.8-22.4 9.6-35.2s-9.6-22.4-19.2-32l-166.4-99.2z","M678.4 364.8c-6.4 0-12.8-3.2-19.2-6.4-16-9.6-19.2-28.8-9.6-44.8l54.4-83.2c9.6-16 28.8-19.2 44.8-9.6 19.2 12.8 22.4 35.2 12.8 48l-54.4 83.2c-6.4 9.6-16 12.8-28.8 12.8z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["dashboard"],"grid":0},"attrs":[{},{},{}],"properties":{"order":26,"id":17,"name":"dashboard","prevSize":24,"code":59665},"setIdx":4,"setId":1,"iconIdx":55},{"icon":{"paths":["M597.35 819.2c14.131 0 25.6-11.469 25.6-25.6v-307.2c0-14.080-11.469-25.6-25.6-25.6s-25.6 11.52-25.6 25.6v307.2c0 14.131 11.418 25.6 25.6 25.6zM776.55 204.8h-153.6v-51.2c0-28.314-22.886-51.2-51.2-51.2h-102.4c-28.262 0-51.2 22.886-51.2 51.2v51.2h-153.6c-28.262 0-51.2 22.886-51.2 51.2v102.4c0 28.314 22.938 51.2 51.2 51.2v460.8c0 28.314 22.938 51.2 51.2 51.2h409.6c28.314 0 51.2-22.886 51.2-51.2v-460.8c28.314 0 51.2-22.886 51.2-51.2v-102.4c0-28.314-22.938-51.2-51.2-51.2zM469.35 153.6h102.4v51.2h-102.4v-51.2zM725.35 870.4h-409.6v-460.8h409.6v460.8zM776.55 358.4h-512v-102.4h512v102.4zM443.75 819.2c14.131 0 25.6-11.469 25.6-25.6v-307.2c0-14.080-11.469-25.6-25.6-25.6s-25.6 11.52-25.6 25.6v307.2c0 14.131 11.469 25.6 25.6 25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["delete"],"grid":0},"attrs":[{}],"properties":{"order":29,"id":18,"name":"delete, bin","prevSize":24,"code":59666},"setIdx":4,"setId":1,"iconIdx":56},{"icon":{"paths":["M832 128h-192v-64c0-35.392-28.608-64-64-64h-128c-35.328 0-64 28.608-64 64v64h-192c-35.328 0-64 28.608-64 64v128c0 35.392 28.672 64 64 64v512c0 35.392 28.672 64 64 64h512c35.392 0 64-28.608 64-64v-512c35.392 0 64-28.608 64-64v-128c0-35.392-28.608-64-64-64zM448 64h128v64h-128v-64zM448 800c0 17.664-14.336 32-32 32s-32-14.336-32-32v-320c0-17.6 14.336-32 32-32s32 14.4 32 32v320zM640 800c0 17.664-14.336 32-32 32s-32-14.336-32-32v-320c0-17.6 14.336-32 32-32s32 14.4 32 32v320zM832 320h-640v-128h640v128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["delete-filled"],"grid":0},"attrs":[{}],"properties":{"order":36,"id":19,"name":"delete-filled","prevSize":24,"code":59667},"setIdx":4,"setId":1,"iconIdx":57},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-343.4zM716.8 189.8l117.4 117.4h-117.4v-117.4zM332.8 460.8c-127.232 0-230.4 103.168-230.4 230.4s103.168 230.4 230.4 230.4c127.232 0 230.4-103.168 230.4-230.4s-103.168-230.4-230.4-230.4zM332.8 512c98.816 0 179.2 80.384 179.2 179.2s-80.384 179.2-179.2 179.2c-98.816 0-179.2-80.384-179.2-179.2s80.384-179.2 179.2-179.2zM227.2 665.6c-12.39 0-22.4 10.061-22.4 22.4v6.4c0 12.39 10.010 22.4 22.4 22.4h211.2c12.39 0 22.4-10.010 22.4-22.4v-6.4c0-12.39-10.061-22.4-22.4-22.4h-211.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-delete"],"grid":0},"attrs":[{}],"properties":{"order":35,"id":20,"name":"document-delete","prevSize":24,"code":59668},"setIdx":4,"setId":1,"iconIdx":58},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-343.4zM716.8 189.8l117.4 117.4h-117.4v-117.4zM332.8 460.8c-127.232 0-230.4 103.168-230.4 230.4s103.168 230.4 230.4 230.4c127.232 0 230.4-103.168 230.4-230.4s-103.168-230.4-230.4-230.4zM332.8 512c39.934 0 76.475 13.533 106.3 35.7l-250.4 249c-21.807-29.683-35.1-65.924-35.1-105.5 0-98.816 80.384-179.2 179.2-179.2zM477 585.7c21.785 29.674 35 65.947 35 105.5 0 98.816-80.384 179.2-179.2 179.2-39.906 0-76.386-13.561-106.2-35.7l250.4-249z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-disable"],"grid":0},"attrs":[{}],"properties":{"order":40,"id":21,"name":"document-disable","prevSize":24,"code":59669},"setIdx":4,"setId":1,"iconIdx":59},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-343.4zM716.8 189.8l117.4 117.4h-117.4v-117.4zM332.8 460.8l-230.4 256v51.2h102.4v153.6h256v-153.6h102.4v-51.2l-230.4-256zM332.8 537.3l161.5 179.5h-84.7v153.6h-153.6v-153.6h-84.7l161.5-179.5z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-publish"],"grid":0},"attrs":[{}],"properties":{"order":44,"id":22,"name":"document-publish","prevSize":24,"code":59670},"setIdx":4,"setId":1,"iconIdx":60},{"icon":{"paths":["M665.6 51.2v102.4h102.4v-102.4h-102.4zM460.8 153.6h102.4v-102.4h-102.4v102.4zM460.8 358.4h102.4v-102.4h-102.4v102.4zM665.6 358.4h102.4v-102.4h-102.4v102.4zM665.6 563.2h102.4v-102.4h-102.4v102.4zM460.8 563.2h102.4v-102.4h-102.4v102.4zM460.8 768h102.4v-102.4h-102.4v102.4zM665.6 768h102.4v-102.4h-102.4v102.4zM665.6 972.8h102.4v-102.4h-102.4v102.4zM460.8 972.8h102.4v-102.4h-102.4v102.4zM256 153.6h102.4v-102.4h-102.4v102.4zM256 358.4h102.4v-102.4h-102.4v102.4zM256 563.2h102.4v-102.4h-102.4v102.4zM256 768h102.4v-102.4h-102.4v102.4zM256 972.8h102.4v-102.4h-102.4v102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["drag"],"grid":0},"attrs":[{}],"properties":{"order":43,"id":23,"name":"drag","prevSize":24,"code":59671},"setIdx":4,"setId":1,"iconIdx":61},{"icon":{"paths":["M921.6 281.958c0-70.707-171.878-128.154-384-128.154s-384 57.19-384 127.898c0 10.035 3.789 19.712 10.342 29.030 0-0.051 296.858 406.067 296.858 406.067v256l153.6-51.2v-204.8c0 0 298.752-408.166 299.725-409.702 0 0 7.475-16.64 7.475-25.139zM537.6 204.8c206.899 0 318.208 53.248 332.083 76.8-13.875 23.552-125.184 76.8-332.083 76.8s-318.208-53.248-332.083-76.8c13.875-23.552 125.184-76.8 332.083-76.8zM869.376 345.856v0 0zM573.030 686.592c-6.4 8.755-9.83 19.354-9.83 30.208v167.885l-51.2 17.050v-184.934c0-10.854-3.43-21.453-9.83-30.208l-228.147-312.115c68.762 21.709 161.382 35.123 263.578 35.123 102.298 0 195.021-13.414 263.834-35.174-0.102 0.051-0.205 0.051-0.307 0.102l-228.096 312.064z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["filter"],"grid":0},"attrs":[{}],"properties":{"order":18,"id":24,"name":"filter","prevSize":24,"code":59672},"setIdx":4,"setId":1,"iconIdx":62},{"icon":{"paths":["M512 0c-282.88 0-512 229.248-512 512 0 226.24 146.688 418.112 350.080 485.76 25.6 4.8 35.008-11.008 35.008-24.64 0-12.16-0.448-44.352-0.64-87.040-142.464 30.912-172.48-68.672-172.48-68.672-23.296-59.136-56.96-74.88-56.96-74.88-46.4-31.744 3.584-31.104 3.584-31.104 51.392 3.584 78.4 52.736 78.4 52.736 45.696 78.272 119.872 55.68 149.12 42.56 4.608-33.088 17.792-55.68 32.448-68.48-113.728-12.8-233.216-56.832-233.216-252.992 0-55.872 19.84-101.568 52.672-137.408-5.76-12.928-23.040-64.96 4.48-135.488 0 0 42.88-13.76 140.8 52.48 40.96-11.392 84.48-17.024 128-17.28 43.52 0.256 87.040 5.888 128 17.28 97.28-66.24 140.16-52.48 140.16-52.48 27.52 70.528 10.24 122.56 5.12 135.488 32.64 35.84 52.48 81.536 52.48 137.408 0 196.672-119.68 240-233.6 252.608 17.92 15.36 34.56 46.72 34.56 94.72 0 68.48-0.64 123.52-0.64 140.16 0 13.44 8.96 29.44 35.2 24.32 204.864-67.136 351.424-259.136 351.424-485.056 0-282.752-229.248-512-512-512z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["brand","github"],"grid":0},"attrs":[{}],"properties":{"order":77,"id":25,"name":"github","prevSize":24,"code":59713},"setIdx":4,"setId":1,"iconIdx":63},{"icon":{"paths":["M512 512h-204.8v51.2h204.8v-51.2zM768 153.6h-51.2c0-28.314-22.886-51.2-51.2-51.2h-307.2c-28.314 0-51.2 22.886-51.2 51.2h-51.2c-28.314 0-51.2 22.886-51.2 51.2v665.6c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-665.6c0-28.314-22.886-51.2-51.2-51.2zM358.4 153.6h307.2v51.2h-307.2v-51.2zM768 819.2c0 28.314-22.886 51.2-51.2 51.2h-409.6c-28.314 0-51.2-22.886-51.2-51.2v-563.2c0-28.314 22.886-51.2 51.2-51.2 0 28.314 22.886 51.2 51.2 51.2h307.2c28.314 0 51.2-22.886 51.2-51.2 28.314 0 51.2 22.886 51.2 51.2v563.2zM307.2 460.8h409.6v-51.2h-409.6v51.2zM307.2 665.6h409.6v-51.2h-409.6v51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["help"],"grid":0},"attrs":[{}],"properties":{"order":19,"id":26,"name":"help","prevSize":24,"code":59673},"setIdx":4,"setId":1,"iconIdx":64},{"icon":{"paths":["M512 0c-169.421 0-307.2 137.779-307.2 307.2 0 78.643 15.258 164.915 45.261 256.41 23.859 72.55 56.986 148.582 98.56 226.099 70.707 131.635 140.339 220.774 143.309 224.512 4.813 6.195 12.288 9.779 20.070 9.779 7.834 0 15.258-3.584 20.122-9.779 2.97-3.686 72.602-92.826 143.309-224.512 41.574-77.517 74.701-153.549 98.56-226.099 29.952-91.494 45.21-177.766 45.21-256.41 0-169.421-137.83-307.2-307.2-307.2zM630.682 764.672c-46.234 86.374-92.979 154.982-118.682 190.822-25.6-35.635-72.038-103.885-118.221-189.952-62.874-117.146-137.779-291.738-137.779-458.342 0-141.158 114.842-256 256-256s256 114.842 256 256c0 166.298-74.65 340.582-137.318 457.472zM512 153.6c-84.685 0-153.6 68.915-153.6 153.6s68.915 153.6 153.6 153.6 153.6-68.915 153.6-153.6-68.915-153.6-153.6-153.6zM512 409.6c-56.525 0-102.4-45.875-102.4-102.4 0-56.474 45.875-102.4 102.4-102.4 56.474 0 102.4 45.926 102.4 102.4 0 56.525-45.926 102.4-102.4 102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["location"],"grid":0},"attrs":[{}],"properties":{"order":25,"id":27,"name":"location, control-Map, type-Geolocation","prevSize":24,"code":59675},"setIdx":4,"setId":1,"iconIdx":65},{"icon":{"paths":["M512.273 83.782c-0.141 0.056-182.959 84.073-229.418 256.782-4.481 16.584 32.696 9.296 31.036 27.527-2.034 22.136-44.668 31.201-39.109 94.764 5.659 64.734 60.321 130.141 68.527 169.673v27.655c-0.497 8.54-4.566 31.715-18.018 43.036-7.378 6.19-17.322 8.421-30.436 6.782-18.205-2.275-25.449-14.468-28.345-24.309-4.753-16.218-0.322-35.123 10.345-44 10.724-8.924 12.17-24.842 3.236-35.564-8.934-10.712-24.858-12.161-35.582-3.218-25.995 21.64-36.887 61.52-26.491 97 9.815 33.392 36.197 55.884 70.6 60.182 4.903 0.609 9.566 0.909 14 0.909 26.623 0 44.661-10.175 55.582-19.455 32.866-27.97 35.449-74.593 35.636-79.818 0.009-0.309 0.018-0.618 0.018-0.927v-21.218h0.109v-1.418c0-12.351 10.008-22.364 22.382-22.364 11.944 0 21.609 9.346 22.273 21.109v202.491c-0.206 2.912-2.536 29.892-17.891 42.945-7.368 6.274-17.384 8.53-30.545 6.873-18.214-2.275-25.476-14.468-28.364-24.291-4.762-16.228-0.322-35.151 10.345-44.018 10.724-8.933 12.188-24.833 3.255-35.564-8.924-10.694-24.876-12.161-35.6-3.218-26.013 21.631-36.887 61.52-26.491 97 9.796 33.392 36.197 55.893 70.6 60.2 4.903 0.609 9.566 0.891 14 0.891 26.623 0 44.671-10.156 55.564-19.436 32.875-27.97 35.458-74.611 35.636-79.836 0.019-0.328 0.018-0.609 0.018-0.909v-225.636l0.127-0.055v-1c0-12.595 10.219-22.8 22.836-22.8 12.349 0 22.333 9.824 22.727 22.073v227.418c0 0.309-0 0.591 0.018 0.909 0.187 5.216 2.779 51.866 35.655 79.836 10.912 9.28 28.959 19.436 55.582 19.436 4.443 0 9.088-0.282 13.982-0.891 34.394-4.307 60.804-26.818 70.6-60.2 10.405-35.48-0.487-75.36-26.491-97-10.743-8.943-26.676-7.466-35.6 3.218-8.934 10.74-7.488 26.63 3.236 35.564 10.668 8.868 15.135 27.79 10.364 44.018-2.878 9.823-10.159 22.015-28.364 24.291-13.105 1.648-23.050-0.592-30.418-6.782-13.508-11.358-17.558-34.657-18.036-43v-201.818c0.297-12.093 10.14-21.818 22.327-21.818 12.374 0 22.4 10.003 22.4 22.364v1.418h0.073v21.218c0 0.318-0 0.628 0.018 0.927 0.178 5.216 2.779 51.848 35.655 79.818 10.912 9.28 28.941 19.455 55.564 19.455 4.434 0 9.107-0.292 14-0.891 34.394-4.298 60.786-26.818 70.582-60.2 10.405-35.48-0.487-75.351-26.491-97-10.743-8.933-26.667-7.476-35.582 3.236-8.943 10.722-7.488 26.622 3.236 35.545 10.668 8.877 15.117 27.8 10.345 44.018-2.878 9.842-10.159 22.025-28.364 24.291-13.086 1.648-23.050-0.583-30.418-6.764-13.508-11.368-17.549-34.675-18.018-43v-21.018c5.305-54.103 63.095-107.777 69.091-176.364 5.531-63.563-37.121-72.627-39.145-94.764-1.669-18.232 35.498-10.944 31.036-27.527-46.468-172.709-229.269-256.726-229.4-256.782z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["logo"],"grid":0},"attrs":[{}],"properties":{"order":31,"id":28,"name":"logo","prevSize":24,"code":59676},"setIdx":4,"setId":1,"iconIdx":66},{"icon":{"paths":["M947.2 0h-870.4c-42.342 0-76.8 34.458-76.8 76.8v870.4c0 42.342 34.458 76.8 76.8 76.8h870.4c42.342 0 76.8-34.458 76.8-76.8v-870.4c0-42.342-34.458-76.8-76.8-76.8zM972.8 947.2c0 14.157-11.443 25.6-25.6 25.6h-870.4c-14.131 0-25.6-11.443-25.6-25.6v-870.4c0-14.131 11.469-25.6 25.6-25.6h870.4c14.157 0 25.6 11.469 25.6 25.6v870.4zM665.6 460.8c56.448 0 102.4-45.926 102.4-102.4s-45.952-102.4-102.4-102.4c-56.448 0-102.4 45.926-102.4 102.4s45.952 102.4 102.4 102.4zM665.6 307.2c28.211 0 51.2 22.989 51.2 51.2s-22.989 51.2-51.2 51.2c-28.211 0-51.2-22.989-51.2-51.2s22.989-51.2 51.2-51.2zM896 102.4h-768c-14.131 0-25.6 11.469-25.6 25.6v614.4c0 14.157 11.469 25.6 25.6 25.6h768c14.157 0 25.6-11.443 25.6-25.6v-614.4c0-14.131-11.443-25.6-25.6-25.6zM153.6 716.8v-118.246l164.301-184.858c4.198-4.787 9.728-7.373 15.462-7.475 5.734-0.051 11.29 2.458 15.642 7.040l283.238 303.539h-478.643zM870.4 716.8h-168.090l-315.853-338.432c-14.285-15.334-33.331-23.603-53.709-23.347-20.326 0.256-39.219 9.011-53.094 24.627l-126.054 141.798v-367.846h716.8v563.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["media"],"grid":0},"attrs":[{}],"properties":{"order":30,"id":29,"name":"media, type-Assets, trigger-AssetChanged","prevSize":24,"code":59677},"setIdx":4,"setId":1,"iconIdx":67},{"icon":{"paths":["M128 384c-70.656 0-128 57.344-128 128s57.344 128 128 128c70.656 0 128-57.344 128-128s-57.344-128-128-128zM512 384c-70.656 0-128 57.344-128 128s57.344 128 128 128c70.656 0 128-57.344 128-128s-57.344-128-128-128zM896 384c-70.656 0-128 57.344-128 128s57.344 128 128 128c70.656 0 128-57.344 128-128s-57.344-128-128-128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["more"],"grid":0},"attrs":[{}],"properties":{"order":34,"id":30,"name":"more, dots","prevSize":24,"code":59678},"setIdx":4,"setId":1,"iconIdx":68},{"icon":{"paths":["M877.12 311.104l-66.304 66.368-228.224-228.224 66.368-66.368c25.216-25.152 66.048-25.152 91.264 0l136.896 137.024c25.216 25.216 25.216 65.984 0 91.2zM760.896 427.392l-386.176 386.112c-25.216 25.28-66.048 25.28-91.264 0l-136.96-136.896c-25.216-25.28-25.216-66.112 0-91.264l386.24-386.24 228.16 228.288zM64 896v-191.872l191.936 191.872h-191.936z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["pencil"],"grid":0},"attrs":[{}],"properties":{"order":47,"id":31,"name":"pencil","prevSize":24,"code":59679},"setIdx":4,"setId":1,"iconIdx":69},{"icon":{"paths":["M892.083 131.917c-73.523-73.498-193.152-73.498-266.65 0l-157.184 157.107c-9.958 10.035-9.958 26.214 0 36.275 10.061 9.984 26.24 9.984 36.25 0l157.133-157.107c53.504-53.555 140.672-53.555 194.176 0 53.581 53.504 53.581 140.672 0 194.176l-186.138 186.163c-53.53 53.581-140.672 53.581-194.176 0-10.086-10.010-26.24-10.010-36.275 0-10.035 10.086-10.035 26.189 0 36.25 36.787 36.736 84.992 55.117 133.325 55.117s96.589-18.432 133.376-55.117l186.163-186.214c73.498-73.472 73.498-193.152 0-266.65zM519.45 698.726l-157.082 157.082c-53.504 53.555-140.672 53.555-194.176 0-53.581-53.504-53.581-140.672 0-194.176l186.138-186.163c53.53-53.581 140.672-53.581 194.176 0 10.086 9.984 26.189 9.984 36.275 0 10.035-10.086 10.035-26.214 0-36.25-73.549-73.498-193.203-73.498-266.701 0l-186.163 186.163c-73.498 73.574-73.498 193.203 0 266.701 36.787 36.71 85.043 55.117 133.325 55.117 48.333 0 96.538-18.406 133.325-55.117l157.133-157.133c10.010-10.010 10.010-26.189 0-36.224-10.010-9.984-26.189-9.984-36.25 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["reference"],"grid":0},"attrs":[{}],"properties":{"order":45,"id":32,"name":"reference","prevSize":24,"code":59680},"setIdx":4,"setId":1,"iconIdx":70},{"icon":{"paths":["M800 1024h-576c-124.8 0-224-99.2-224-224v-300.8c0-124.8 99.2-224 224-224h576c124.8 0 224 99.2 224 224v300.8c0 124.8-99.2 224-224 224zM224 339.2c-89.6 0-160 70.4-160 160v300.8c0 89.6 70.4 160 160 160h576c89.6 0 160-70.4 160-160v-300.8c0-89.6-70.4-160-160-160h-576z","M828.8 201.6h-633.6c-19.2 0-32-12.8-32-32s12.8-32 32-32h630.4c19.2 0 32 12.8 32 32s-12.8 32-28.8 32z","M716.8 64h-409.6c-19.2 0-32-12.8-32-32s12.8-32 32-32h412.8c19.2 0 32 12.8 32 32s-16 32-35.2 32z","M800 416v64c0 48-38.4 83.2-83.2 83.2h-409.6c-44.8 3.2-83.2-35.2-83.2-83.2v-64h-54.4v64c0 76.8 64 140.8 140.8 140.8h406.4c76.8 0 140.8-64 140.8-140.8v-64h-57.6z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["schemas"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":46,"id":33,"name":"schemas","prevSize":24,"code":59681},"setIdx":4,"setId":1,"iconIdx":71},{"icon":{"paths":["M939.776 1003.776c-27.2 27.008-71.232 27.008-98.368 0l-168.96-168.96c-66.176 38.464-142.016 62.080-224 62.080-247.744 0-448.448-200.832-448.448-448.448 0-247.744 200.704-448.448 448.448-448.448 247.68 0 448.512 200.704 448.512 448.448 0 115.136-44.672 218.944-115.904 298.304l158.656 158.656c27.008 27.136 27.008 71.168 0.064 98.368zM448.448 128.128c-176.896 0-320.32 143.36-320.32 320.32s143.424 320.32 320.32 320.32c176.96 0 320.384-143.36 320.384-320.32s-143.488-320.32-320.384-320.32z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["search"],"grid":0},"attrs":[{}],"properties":{"order":23,"id":34,"name":"search","prevSize":24,"code":59682},"setIdx":4,"setId":1,"iconIdx":72},{"icon":{"paths":["M1019.11 440.755c-1.946-13.747-14.438-23.398-28.16-21.888-16.947 1.843-34.253-0.589-50.048-7.091-52.25-21.504-77.261-81.459-55.757-133.709 6.605-15.846 16.947-29.85 30.208-40.602 10.803-8.653 12.698-24.294 4.352-35.354-28.902-37.99-62.797-71.706-100.838-100.045-10.701-8.090-25.805-6.451-34.662 3.661-28.8 33.254-75.546 44.262-116.198 27.546-40.704-16.742-66.099-57.498-63.206-101.453 0.845-13.338-8.755-25.19-21.99-27.008-47.002-6.605-94.797-6.605-142.054 0.077-13.722 1.946-23.398 14.387-21.862 28.211 1.843 16.896-0.614 34.202-7.168 49.997-21.504 52.25-81.408 77.21-133.632 55.706-15.821-6.502-29.85-16.947-40.602-30.157-8.653-10.752-24.32-12.698-35.379-4.301-37.99 28.851-71.68 62.694-100.045 100.762-8.090 10.701-6.451 25.83 3.635 34.637 33.28 28.902 44.288 75.597 27.546 116.301-16.742 40.653-57.498 66.048-101.427 63.155-13.363-0.845-25.19 8.755-26.982 21.99-6.63 47.002-6.63 94.822 0.102 142.080 1.946 13.696 14.387 23.322 28.16 21.811 16.896-1.818 34.202 0.691 50.022 7.168 52.224 21.53 77.21 81.459 55.706 133.734-6.502 15.795-16.947 29.773-30.157 40.525-10.803 8.73-12.698 24.346-4.352 35.354 28.877 38.042 62.822 71.731 100.813 100.122 1.741 1.357 3.661 2.355 5.606 3.2 9.933 4.045 21.709 1.536 29.082-6.938 28.826-33.178 75.571-44.262 116.275-27.52 40.653 16.742 66.048 57.498 63.13 101.453-0.819 13.338 8.755 25.165 22.067 27.059 47.002 6.579 94.72 6.554 142.029-0.102 13.645-1.971 23.347-14.464 21.811-28.237-1.843-16.947 0.691-34.253 7.194-50.048 21.504-52.25 81.459-77.21 133.658-55.68 15.795 6.528 29.85 16.947 40.55 30.157 8.704 10.803 24.346 12.698 35.405 4.326 37.99-28.902 71.654-62.746 100.096-100.813 7.987-10.675 6.4-25.805-3.712-34.662-33.254-28.826-44.288-75.571-27.546-116.224 16.742-40.73 57.498-66.099 101.453-63.232 13.338 0.922 25.139-8.678 27.008-21.965 6.554-47.002 6.502-94.771-0.128-142.003zM971.059 554.010c-56.141 5.274-105.702 41.114-127.642 94.464s-12.058 113.613 24.090 156.902c-17.69 21.478-37.453 41.318-58.854 59.315-12.749-11.213-27.392-20.352-43.238-26.854-78.259-32.282-168.243 5.197-200.499 83.584-6.502 15.718-10.291 32.563-11.29 49.536-27.853 2.56-55.859 2.637-83.61 0.077-5.274-56.090-41.114-105.677-94.464-127.616-53.35-21.99-113.613-11.981-156.928 24.064-21.504-17.69-41.318-37.453-59.29-58.88 11.213-12.723 20.352-27.392 26.906-43.136 32.205-78.387-5.274-168.294-83.584-200.55-15.821-6.502-32.589-10.342-49.613-11.366-2.534-27.853-2.586-55.859 0-83.558 56.090-5.299 105.626-41.088 127.565-94.438 21.965-53.402 12.058-113.638-24.090-156.902 17.69-21.555 37.478-41.395 58.88-59.341 12.749 11.213 27.392 20.352 43.213 26.854 78.285 32.256 168.218-5.248 200.474-83.558 6.528-15.795 10.342-32.589 11.366-49.613 27.853-2.509 55.808-2.56 83.558 0 5.299 56.090 41.139 105.6 94.49 127.59 53.35 21.939 113.638 12.006 156.902-24.090 21.504 17.741 41.293 37.453 59.29 58.854-11.213 12.8-20.352 27.392-26.854 43.213-32.256 78.31 5.248 168.294 83.507 200.499 15.846 6.502 32.691 10.342 49.638 11.392 2.56 27.853 2.611 55.808 0.077 83.558zM512 307.2c-113.101 0-204.8 91.699-204.8 204.8 0 113.126 91.699 204.826 204.8 204.826s204.8-91.699 204.8-204.826c0-113.101-91.699-204.8-204.8-204.8zM512 665.626c-84.813 0-153.6-68.813-153.6-153.626 0-84.838 68.787-153.6 153.6-153.6 84.838 0 153.6 68.762 153.6 153.6 0 84.813-68.762 153.626-153.6 153.626z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["settings"],"grid":0},"attrs":[{}],"properties":{"order":22,"id":35,"name":"settings","prevSize":24,"code":59683},"setIdx":4,"setId":1,"iconIdx":73},{"icon":{"paths":["M77.005 102.605h128v332.8c0 14.131 11.418 25.6 25.6 25.6 14.106 0 25.6-11.469 25.6-25.6v-332.8h128c14.106 0 25.6-11.469 25.6-25.6 0-14.157-11.494-25.6-25.6-25.6h-307.2c-14.182 0-25.6 11.443-25.6 25.6 0 14.106 11.418 25.6 25.6 25.6zM947.405 716.979h-179.2v-102.4h179.2c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-204.8c-14.182 0-25.6 11.443-25.6 25.6v358.4c0 14.157 11.418 25.6 25.6 25.6 14.157 0 25.6-11.443 25.6-25.6v-179.2h179.2c14.157 0 25.6-11.443 25.6-25.6s-11.494-25.6-25.6-25.6zM965.094 58.47c-9.958-9.933-26.112-9.933-36.045 0l-870.605 870.579c-9.958 9.984-9.958 26.086 0 36.045 10.010 9.984 26.112 9.984 36.045 0l870.605-870.579c9.958-9.933 9.958-26.086 0-36.045z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-boolean"],"grid":0},"attrs":[{}],"properties":{"order":21,"id":36,"name":"type-Boolean","prevSize":24,"code":59684},"setIdx":4,"setId":1,"iconIdx":74},{"icon":{"paths":["M947.2 102.4h-128v-25.6c0-14.131-11.469-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-512v-25.6c0-14.131-11.52-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-128c-42.342 0-76.8 34.458-76.8 76.8v716.8c0 42.342 34.458 76.8 76.8 76.8h870.4c42.342 0 76.8-34.458 76.8-76.8v-716.8c0-42.342-34.458-76.8-76.8-76.8zM972.8 896c0 14.131-11.469 25.6-25.6 25.6h-870.4c-14.080 0-25.6-11.469-25.6-25.6v-537.6h921.6v537.6zM972.8 307.2h-921.6v-128c0-14.080 11.52-25.6 25.6-25.6h128v76.8c0 14.080 11.52 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h512v76.8c0 14.080 11.469 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h128c14.131 0 25.6 11.52 25.6 25.6v128zM332.8 512h51.2c14.080 0 25.6-11.52 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM640 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-datetime"],"grid":0},"attrs":[{}],"properties":{"order":24,"id":37,"name":"type-DateTime","prevSize":24,"code":59685},"setIdx":4,"setId":1,"iconIdx":75},{"icon":{"paths":["M179.2 256c0-28.262 22.938-51.2 51.2-51.2h25.6c14.157 0 25.6-11.443 25.6-25.6 0-14.131-11.443-25.6-25.6-25.6h-25.6c-56.55 0-102.4 45.85-102.4 102.4v179.2c0 28.262-22.938 51.2-51.2 51.2h-25.6c-14.157 0-25.6 11.469-25.6 25.6 0 14.157 11.443 25.6 25.6 25.6h25.6c28.262 0 51.2 22.938 51.2 51.2v179.2c0 56.55 45.85 102.4 102.4 102.4h25.6c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-25.6c-28.262 0-51.2-22.938-51.2-51.2v-179.2c0-30.746-13.85-58.061-35.328-76.8 21.478-18.765 35.328-46.029 35.328-76.8v-179.2zM972.8 486.4h-25.6c-28.262 0-51.2-22.938-51.2-51.2v-179.2c0-56.55-45.85-102.4-102.4-102.4h-25.6c-14.157 0-25.6 11.469-25.6 25.6 0 14.157 11.443 25.6 25.6 25.6h25.6c28.262 0 51.2 22.938 51.2 51.2v179.2c0 30.771 13.85 58.035 35.328 76.8-21.478 18.739-35.328 46.054-35.328 76.8v179.2c0 28.262-22.938 51.2-51.2 51.2h-25.6c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h25.6c56.55 0 102.4-45.85 102.4-102.4v-179.2c0-28.262 22.938-51.2 51.2-51.2h25.6c14.157 0 25.6-11.443 25.6-25.6 0-14.131-11.443-25.6-25.6-25.6zM512 332.8c-14.157 0-25.6 11.469-25.6 25.6 0 14.157 11.443 25.6 25.6 25.6s25.6-11.443 25.6-25.6c0-14.131-11.443-25.6-25.6-25.6zM512 435.2c-14.157 0-25.6 11.469-25.6 25.6v204.8c0 14.157 11.443 25.6 25.6 25.6s25.6-11.443 25.6-25.6v-204.8c0-14.131-11.443-25.6-25.6-25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["json"],"grid":0},"attrs":[{}],"properties":{"order":20,"id":38,"name":"type-Json, json","prevSize":24,"code":59674},"setIdx":4,"setId":1,"iconIdx":76},{"icon":{"paths":["M256 665.6h-76.8v-332.8c0-14.131-11.469-25.6-25.6-25.6h-76.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h51.2v307.2h-76.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h204.8c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6zM614.4 307.2h-204.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h179.2v128h-179.2c-14.131 0-25.6 11.469-25.6 25.6v179.2c0 14.131 11.469 25.6 25.6 25.6h204.8c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-179.2v-128h179.2c14.131 0 25.6-11.469 25.6-25.6v-179.2c0-14.131-11.469-25.6-25.6-25.6zM972.8 307.2h-204.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h179.2v128h-179.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h179.2v128h-179.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h204.8c14.131 0 25.6-11.469 25.6-25.6v-358.4c0-14.131-11.469-25.6-25.6-25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-number"],"grid":0},"attrs":[{}],"properties":{"order":32,"id":39,"name":"type-Number","prevSize":24,"code":59686},"setIdx":4,"setId":1,"iconIdx":77},{"icon":{"paths":["M870.4 921.6h-716.8c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h716.8c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6zM194.688 817.152c13.030 5.555 28.083-0.461 33.613-13.44l125.030-291.712h317.338l125.005 291.712c4.173 9.677 13.568 15.488 23.526 15.488 3.405 0 6.81-0.64 10.112-2.048 13.005-5.606 18.995-20.659 13.44-33.638l-131.61-306.944c-0.051-0.051-0.051-0.154-0.102-0.205l-175.488-409.6c-4.045-9.472-13.312-15.565-23.552-15.565s-19.507 6.093-23.552 15.514l-175.488 409.6c-0.051 0.051-0.051 0.154-0.102 0.205l-131.61 306.97c-5.53 13.005 0.461 28.058 13.44 33.664zM512 141.773l136.704 319.027h-273.408l136.704-319.027z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-string"],"grid":0},"attrs":[{}],"properties":{"order":48,"id":40,"name":"type-String","prevSize":24,"code":59687},"setIdx":4,"setId":1,"iconIdx":78},{"icon":{"paths":["M955.221 848c0-0.109 10.752 0 0 0-52.751-161.392-240.461-224-443.178-224-202.269 0-389.979 63.392-443.066 224-11.2-0.109 0-1.232 0 0 0 61.936 49.615 112 110.654 112h664.823c61.151 0 110.766-50.064 110.766-112zM290.399 288c0 123.648 99.231 336 221.645 336s221.645-212.352 221.645-336c0-123.648-99.231-224-221.645-224s-221.645 100.352-221.645 224z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["user"],"grid":0},"attrs":[{}],"properties":{"order":33,"id":41,"name":"user","prevSize":24,"code":59688},"setIdx":4,"setId":1,"iconIdx":79},{"icon":{"paths":["M469.333 614.997v281.003c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-281.003l97.835 97.835c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-170.667-170.667c-0.085-0.085-0.171-0.171-0.256-0.256-4.053-3.968-8.661-6.955-13.568-9.003-5.12-2.133-10.624-3.2-16.085-3.243-0.171 0-0.341 0-0.469 0-5.461 0.043-10.965 1.109-16.085 3.243-4.949 2.048-9.557 5.035-13.568 9.003-0.085 0.085-0.171 0.171-0.256 0.256l-170.667 170.667c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0zM890.411 822.101c30.379-16.555 56.149-38.443 76.672-63.915 21.333-26.411 36.949-56.619 46.379-88.576s12.629-65.835 9.003-99.584c-3.456-32.512-13.269-64.896-29.824-95.232-14.208-26.069-32.384-48.768-53.376-67.669-21.717-19.541-46.421-34.944-72.875-45.952-30.891-12.8-64.171-19.584-98.048-19.84h-22.528c-13.312-37.717-32.085-72.235-55.168-102.912-30.635-40.661-68.821-74.453-111.915-99.84s-91.179-42.411-141.568-49.536c-48.597-6.784-99.243-4.395-149.504 8.619s-95.744 35.413-134.912 64.939c-40.661 30.635-74.453 68.821-99.84 111.915s-42.411 91.179-49.493 141.568c-6.827 48.555-4.395 99.2 8.576 149.461 15.872 61.312 45.781 115.627 84.267 158.421 15.744 17.536 42.752 18.944 60.245 3.2s18.944-42.752 3.2-60.245c-29.355-32.64-52.693-74.667-65.109-122.752-10.155-39.253-11.989-78.592-6.699-116.224 5.504-39.125 18.773-76.501 38.571-110.123s46.080-63.317 77.653-87.083c30.379-22.869 65.664-40.32 104.917-50.475s78.592-11.989 116.224-6.699c39.125 5.504 76.544 18.731 110.123 38.528s63.317 46.080 87.083 77.653c22.869 30.379 40.32 65.664 50.475 104.917 4.907 18.56 21.547 32 41.301 32h53.461c22.869 0.171 45.269 4.736 65.92 13.312 17.707 7.339 34.133 17.621 48.512 30.592 13.909 12.501 25.984 27.605 35.541 45.099 11.093 20.352 17.579 41.899 19.883 63.488 2.389 22.443 0.256 45.013-6.016 66.432s-16.725 41.515-30.933 59.093c-13.611 16.896-30.763 31.445-51.115 42.581-20.693 11.264-28.331 37.205-17.024 57.899s37.205 28.331 57.899 17.024z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["upload-cloud"],"grid":0},"attrs":[{}],"properties":{"order":1,"id":2,"prevSize":24,"code":59763,"name":"upload-3"},"setIdx":4,"setId":1,"iconIdx":80},{"icon":{"paths":["M853.333 640v170.667c0 5.845-1.152 11.349-3.2 16.299-2.133 5.205-5.333 9.899-9.301 13.867s-8.661 7.125-13.867 9.301c-4.949 2.048-10.453 3.2-16.299 3.2h-597.333c-5.845 0-11.349-1.152-16.299-3.2-5.205-2.133-9.899-5.333-13.867-9.301s-7.125-8.661-9.301-13.867c-2.048-4.949-3.2-10.453-3.2-16.299v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v170.667c0 17.28 3.456 33.835 9.728 48.981 6.485 15.701 16 29.781 27.776 41.557s25.856 21.291 41.557 27.776c15.104 6.229 31.659 9.685 48.939 9.685h597.333c17.28 0 33.835-3.456 48.981-9.728 15.701-6.485 29.781-16 41.557-27.776s21.291-25.856 27.776-41.557c6.229-15.104 9.685-31.659 9.685-48.939v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM469.333 230.997v409.003c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-409.003l140.501 140.501c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-213.333-213.333c-0.043-0.043-0.128-0.085-0.171-0.171-4.053-4.011-8.704-7.040-13.653-9.088-10.453-4.309-22.229-4.309-32.683 0-4.949 2.048-9.6 5.077-13.653 9.088-0.043 0.043-0.128 0.085-0.171 0.171l-213.333 213.333c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["upload"],"grid":0},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":24,"code":59761,"name":"upload-4"},"setIdx":4,"setId":1,"iconIdx":81},{"icon":{"paths":["M470 384v-86h84v86h-84zM512 854c188 0 342-154 342-342s-154-342-342-342-342 154-342 342 154 342 342 342zM512 86c236 0 426 190 426 426s-190 426-426 426-426-190-426-426 190-426 426-426zM470 726v-256h84v256h-84z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["info_outline"],"grid":24},"attrs":[{}],"properties":{"order":128,"id":0,"prevSize":24,"code":59764,"name":"info-outline"},"setIdx":2,"setId":3,"iconIdx":0},{"icon":{"paths":["M214 768h596v86h-596v-86zM384 682v-256h-170l298-298 298 298h-170v256h-256z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["file_upload"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59762,"name":"upload-2"},"setIdx":4,"setId":1,"iconIdx":0},{"icon":{"paths":["M678 726h138l-70-186zM790 426l192 512h-86l-48-128h-202l-48 128h-86l192-512h86zM550 642l-34 88-132-132-214 212-60-60 218-214c-54-60-96-124-128-194h86c26 50 58 98 98 142 62-68 108-146 136-228h-478v-86h300v-84h84v84h300v86h-126c-32 100-84 196-158 278l-2 2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["translate"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59759,"name":"translate"},"setIdx":4,"setId":1,"iconIdx":1},{"icon":{"paths":["M854 470v84h-520l238 240-60 60-342-342 342-342 60 60-238 240h520z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow_back"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":24,"code":59758,"name":"arrow_back"},"setIdx":4,"setId":1,"iconIdx":2},{"icon":{"paths":["M768 512c-25.6 0-42.667 17.067-42.667 42.667v256c0 25.6-17.067 42.667-42.667 42.667h-469.333c-25.6 0-42.667-17.067-42.667-42.667v-469.333c0-25.6 17.067-42.667 42.667-42.667h256c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667h-256c-72.533 0-128 55.467-128 128v469.333c0 72.533 55.467 128 128 128h469.333c72.533 0 128-55.467 128-128v-256c0-25.6-17.067-42.667-42.667-42.667z","M934.4 110.933c-4.267-8.533-12.8-17.067-21.333-21.333-4.267-4.267-12.8-4.267-17.067-4.267h-256c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h153.6l-396.8 396.8c-17.067 17.067-17.067 42.667 0 59.733 8.533 8.533 17.067 12.8 29.867 12.8s21.333-4.267 29.867-12.8l396.8-396.8v153.6c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-256c0-4.267 0-12.8-4.267-17.067z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["external-link"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":2,"prevSize":24,"code":59757,"name":"external-link"},"setIdx":4,"setId":1,"iconIdx":3},{"icon":{"paths":["M810.667 85.333h-597.333c-72.533 0-128 55.467-128 128v597.333c0 72.533 55.467 128 128 128h597.333c72.533 0 128-55.467 128-128v-597.333c0-72.533-55.467-128-128-128zM853.333 810.667c0 25.6-17.067 42.667-42.667 42.667h-597.333c-25.6 0-42.667-17.067-42.667-42.667v-597.333c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v597.333z","M682.667 469.333h-341.333c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h341.333c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["minus-square"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":3,"prevSize":24,"code":59753,"name":"minus-square"},"setIdx":4,"setId":1,"iconIdx":4},{"icon":{"paths":["M810.667 85.333h-597.333c-72.533 0-128 55.467-128 128v597.333c0 72.533 55.467 128 128 128h597.333c72.533 0 128-55.467 128-128v-597.333c0-72.533-55.467-128-128-128zM853.333 810.667c0 25.6-17.067 42.667-42.667 42.667h-597.333c-25.6 0-42.667-17.067-42.667-42.667v-597.333c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v597.333z","M682.667 469.333h-128v-128c0-25.6-17.067-42.667-42.667-42.667s-42.667 17.067-42.667 42.667v128h-128c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h128v128c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-128h128c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["plus-square"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":4,"name":"plus-square","prevSize":24,"code":59752},"setIdx":4,"setId":1,"iconIdx":5},{"icon":{"paths":["M170 640v-86h684v86h-684zM854 384v86h-684v-86h684z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["drag_handle"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":5,"prevSize":24,"code":59745,"name":"drag2"},"setIdx":4,"setId":1,"iconIdx":6},{"icon":{"paths":["M854 682v-512h-684v598l86-86h598zM854 86c46 0 84 38 84 84v512c0 46-38 86-84 86h-598l-170 170v-768c0-46 38-84 84-84h684z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["chat_bubble_outline"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":6,"name":"comments","prevSize":24,"code":59743},"setIdx":4,"setId":1,"iconIdx":7},{"icon":{"paths":["M512 128c212 0 384 172 384 384s-172 384-384 384c-88 0-170-30-234-80l60-60c50 34 110 54 174 54 166 0 298-132 298-298s-132-298-298-298-298 132-298 298h128l-172 170-170-170h128c0-212 172-384 384-384zM598 512c0 46-40 86-86 86s-86-40-86-86 40-86 86-86 86 40 86 86z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["settings_backup_restore"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":7,"prevSize":24,"code":59739,"name":"backup"},"setIdx":4,"setId":1,"iconIdx":8},{"icon":{"paths":["M726 512c0 24-20 42-44 42h-426l-170 172v-598c0-24 18-42 42-42h554c24 0 44 18 44 42v384zM896 256c24 0 42 18 42 42v640l-170-170h-470c-24 0-42-18-42-42v-86h554v-384h86z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["question_answer"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":8,"prevSize":24,"code":59738,"name":"support"},"setIdx":4,"setId":1,"iconIdx":9},{"icon":{"paths":["M918 384v128h-128v298h-128v-298h-128v-128h384zM106 170h556v128h-214v512h-128v-512h-214v-128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["text_fields"],"grid":24},"attrs":[{}],"properties":{"order":75,"id":9,"prevSize":24,"code":59705,"name":"control-RichText"},"setIdx":4,"setId":1,"iconIdx":10},{"icon":{"paths":["M640 85.333q78 0 149.167 30.5t122.5 81.833 81.833 122.5 30.5 149.167q0 85-35 160.667t-96.667 129.167-140 77.5l21-20.667q18-18.333 28-42.667 9.333-22.667 9.333-49.333 0-6.667-0.333-9.333 59.333-41.333 93.833-105.833t34.5-139.5q0-60.667-23.667-116t-63.667-95.333-95.333-63.667-116-23.667q-55.333 0-106.5 19.833t-90 53.833-65 81.333-33.833 101h-88.667q-70.667 0-120.667 50t-50 120.667q0 38.667 15.167 71.667t39.833 54.167 54.833 33 60.833 11.833h50q11.667 29.333 30 48l37.667 37.333h-117.667q-69.667 0-128.5-34.333t-93.167-93.167-34.333-128.5 34.333-128.5 93.167-93.167 128.5-34.333h22q26.333-74.333 79.333-132.167t126.833-90.833 155.833-33zM554.667 426.667q17.667 0 30.167 12.5t12.5 30.167v281l55-55.333q12.333-12.333 30.333-12.333 18.333 0 30.5 12.167t12.167 30.5q0 18-12.333 30.333l-128 128q-12.333 12.333-30.333 12.333t-30.333-12.333l-128-128q-12.333-13-12.333-30.333 0-17.667 12.5-30.167t30.167-12.5q18 0 30.333 12.333l55 55.333v-281q0-17.667 12.5-30.167t30.167-12.5z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["cloud-download"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":10,"prevSize":24,"code":59710,"name":"download"},"setIdx":4,"setId":1,"iconIdx":11},{"icon":{"paths":["M621.254 877.254l320-320c24.994-24.992 24.994-65.516 0-90.51l-320-320c-24.994-24.992-65.516-24.992-90.51 0-24.994 24.994-24.994 65.516 0 90.51l210.746 210.746h-613.49c-35.346 0-64 28.654-64 64s28.654 64 64 64h613.49l-210.746 210.746c-12.496 12.496-18.744 28.876-18.744 45.254s6.248 32.758 18.744 45.254c24.994 24.994 65.516 24.994 90.51 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-right","right","next"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":32,"code":59766,"name":"arrow-right"},"setIdx":3,"setId":2,"iconIdx":0},{"icon":{"paths":["M448 576h128v-256h192l-256-256-256 256h192zM640 432v98.712l293.066 109.288-421.066 157.018-421.066-157.018 293.066-109.288v-98.712l-384 144v256l512 192 512-192v-256z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["upload","load","arrow"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":32,"code":59760,"name":"upload"},"setIdx":4,"setId":1,"iconIdx":12},{"icon":{"paths":["M585.143 548.557c0 9.728-3.986 18.871-10.862 25.71l-256 256c-6.839 6.839-16.018 10.862-25.71 10.862s-18.871-3.986-25.71-10.862l-256-256c-6.839-6.839-10.862-16.018-10.862-25.71 0-20.005 16.567-36.571 36.571-36.571h512c20.005 0 36.571 16.567 36.571 36.571z","M585.143 219.443c0 9.728-3.986 18.871-10.862 25.71l-256 256c-6.839 6.839-16.018 10.862-25.71 10.862s-18.871-3.986-25.71-10.862l-256-256c-6.839-6.839-10.862-16.018-10.862-25.71 0-20.005 16.567-36.571 36.571-36.571h512c20.005 0 36.571 16.567 36.571 36.571z"],"width":585,"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-bottom"],"grid":16},"attrs":[{},{}],"properties":{"order":125,"id":0,"name":"caret-bottom","prevSize":32,"code":59755},"setIdx":4,"setId":1,"iconIdx":13},{"icon":{"paths":["M585.143 804.577c0 20.005-16.567 36.571-36.571 36.571h-512c-20.005 0-36.571-16.567-36.571-36.571 0-9.728 3.986-18.871 10.862-25.71l256-256c6.839-6.839 16.018-10.862 25.71-10.862s18.871 3.986 25.71 10.862l256 256c6.839 6.839 10.862 16.018 10.862 25.71z","M585.143 475.423c0 20.005-16.567 36.571-36.571 36.571h-512c-20.005 0-36.571-16.567-36.571-36.571 0-9.728 3.986-18.871 10.862-25.71l256-256c6.839-6.839 16.018-10.862 25.71-10.862s18.871 3.986 25.71 10.862l256 256c6.839 6.839 10.862 16.018 10.862 25.71z"],"width":585,"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-top"],"grid":16},"attrs":[{},{}],"properties":{"order":124,"id":1,"name":"caret-top","prevSize":32,"code":59756},"setIdx":4,"setId":1,"iconIdx":14},{"icon":{"paths":["M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M408.906 587.72l-35.3-37 138.1-131.9 138 131.9-35.3 37-102.7-98.1z","M511.706 773.12l-138.1-131.9 35.3-37 102.8 98.1 102.7-98.1 35.3 37z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["show"],"grid":16},"attrs":[{},{},{}],"properties":{"order":123,"id":2,"name":"show","prevSize":32,"code":59748},"setIdx":4,"setId":1,"iconIdx":15},{"icon":{"paths":["M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M348.394 15.988c-28.314 0-51.2 22.886-51.2 51.2v23.7h51.2v-23.7h307.2l204.8 204.8v512h-23.8v51.2h23.8c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2z","M408.906 587.72l-35.3-37 138.1-131.9 138 131.9-35.3 37-102.7-98.1z","M511.706 773.12l-138.1-131.9 35.3-37 102.8 98.1 102.7-98.1 35.3 37z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["show-all"],"grid":16},"attrs":[{},{},{},{}],"properties":{"order":122,"id":3,"name":"show-all","prevSize":32,"code":59749},"setIdx":4,"setId":1,"iconIdx":16},{"icon":{"paths":["M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M408.9 418.8l-35.3 37 138 131.9 138.1-131.9-35.3-37-102.8 98.1z","M511.6 604.2l-138 131.9 35.3 37 102.7-98.1 102.8 98.1 35.3-37z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["hide"],"grid":16},"attrs":[{},{},{}],"properties":{"order":121,"id":4,"name":"hide","prevSize":32,"code":59750},"setIdx":4,"setId":1,"iconIdx":17},{"icon":{"paths":["M408.9 418.8l-35.3 37 138.1 131.9 138-131.9-35.3-37-102.7 98.1z","M511.7 604.2l-138.1 131.9 35.3 37 102.8-98.1 102.7 98.1 35.3-37z","M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M348.394 15.988c-28.314 0-51.2 22.886-51.2 51.2v23.7h51.2v-23.7h307.2l204.8 204.8v512h-23.8v51.2h23.8c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["hide-all"],"grid":16},"attrs":[{},{},{},{}],"properties":{"order":120,"id":5,"name":"hide-all","prevSize":32,"code":59751},"setIdx":4,"setId":1,"iconIdx":18},{"icon":{"paths":["M512 1024c-136.76 0-265.334-53.258-362.040-149.96-96.702-96.706-149.96-225.28-149.96-362.040 0-96.838 27.182-191.134 78.606-272.692 50-79.296 120.664-143.372 204.356-185.3l43 85.832c-68.038 34.084-125.492 86.186-166.15 150.67-41.746 66.208-63.812 142.798-63.812 221.49 0 229.382 186.618 416 416 416s416-186.618 416-416c0-78.692-22.066-155.282-63.81-221.49-40.66-64.484-98.114-116.584-166.15-150.67l43-85.832c83.692 41.928 154.358 106.004 204.356 185.3 51.422 81.558 78.604 175.854 78.604 272.692 0 136.76-53.258 265.334-149.96 362.040-96.706 96.702-225.28 149.96-362.040 149.96z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["spinner","loading","loading-wheel","busy","wait"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":6,"prevSize":32,"code":59737,"name":"spinner2"},"setIdx":4,"setId":1,"iconIdx":19},{"icon":{"paths":["M1024 397.050l-353.78-51.408-158.22-320.582-158.216 320.582-353.784 51.408 256 249.538-60.432 352.352 316.432-166.358 316.432 166.358-60.434-352.352 256.002-249.538z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["star-full","rate","star","favorite","bookmark"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":7,"prevSize":32,"code":59741,"name":"star-full"},"setIdx":4,"setId":1,"iconIdx":20},{"icon":{"paths":["M1024 397.050l-353.78-51.408-158.22-320.582-158.216 320.582-353.784 51.408 256 249.538-60.432 352.352 316.432-166.358 316.432 166.358-60.434-352.352 256.002-249.538zM512 753.498l-223.462 117.48 42.676-248.83-180.786-176.222 249.84-36.304 111.732-226.396 111.736 226.396 249.836 36.304-180.788 176.222 42.678 248.83-223.462-117.48z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["star-empty","rate","star","favorite","bookmark"],"grid":16},"attrs":[{}],"properties":{"order":2,"id":8,"prevSize":32,"code":59742,"name":"star-empty"},"setIdx":4,"setId":1,"iconIdx":21},{"icon":{"paths":["M1024 226.4c-37.6 16.8-78.2 28-120.6 33 43.4-26 76.6-67.2 92.4-116.2-40.6 24-85.6 41.6-133.4 51-38.4-40.8-93-66.2-153.4-66.2-116 0-210 94-210 210 0 16.4 1.8 32.4 5.4 47.8-174.6-8.8-329.4-92.4-433-219.6-18 31-28.4 67.2-28.4 105.6 0 72.8 37 137.2 93.4 174.8-34.4-1-66.8-10.6-95.2-26.2 0 0.8 0 1.8 0 2.6 0 101.8 72.4 186.8 168.6 206-17.6 4.8-36.2 7.4-55.4 7.4-13.6 0-26.6-1.4-39.6-3.8 26.8 83.4 104.4 144.2 196.2 146-72 56.4-162.4 90-261 90-17 0-33.6-1-50.2-3 93.2 59.8 203.6 94.4 322.2 94.4 386.4 0 597.8-320.2 597.8-597.8 0-9.2-0.2-18.2-0.6-27.2 41-29.4 76.6-66.4 104.8-108.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["twitter","brand","tweet","social"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":9,"prevSize":32,"code":59740,"name":"twitter"},"setIdx":4,"setId":1,"iconIdx":22},{"icon":{"paths":["M728.992 512c137.754-87.334 231.008-255.208 231.008-448 0-21.676-1.192-43.034-3.478-64h-889.042c-2.29 20.968-3.48 42.326-3.48 64 0 192.792 93.254 360.666 231.006 448-137.752 87.334-231.006 255.208-231.006 448 0 21.676 1.19 43.034 3.478 64h889.042c2.288-20.966 3.478-42.324 3.478-64 0.002-192.792-93.252-360.666-231.006-448zM160 960c0-186.912 80.162-345.414 224-397.708v-100.586c-143.838-52.29-224-210.792-224-397.706v0h704c0 186.914-80.162 345.416-224 397.706v100.586c143.838 52.294 224 210.796 224 397.708h-704zM619.626 669.594c-71.654-40.644-75.608-93.368-75.626-125.366v-64.228c0-31.994 3.804-84.914 75.744-125.664 38.504-22.364 71.808-56.348 97.048-98.336h-409.582c25.266 42.032 58.612 76.042 97.166 98.406 71.654 40.644 75.606 93.366 75.626 125.366v64.228c0 31.992-3.804 84.914-75.744 125.664-72.622 42.18-126.738 125.684-143.090 226.336h501.67c-16.364-100.708-70.53-184.248-143.212-226.406z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["hour-glass","loading","busy","wait"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":10,"prevSize":32,"code":59732,"name":"hour-glass"},"setIdx":4,"setId":1,"iconIdx":23},{"icon":{"paths":["M192 512c0-12.18 0.704-24.196 2.030-36.022l-184.98-60.104c-5.916 31.14-9.050 63.264-9.050 96.126 0 147.23 62.166 279.922 161.654 373.324l114.284-157.296c-52.124-56.926-83.938-132.758-83.938-216.028zM832 512c0 83.268-31.812 159.102-83.938 216.028l114.284 157.296c99.488-93.402 161.654-226.094 161.654-373.324 0-32.862-3.132-64.986-9.048-96.126l-184.98 60.104c1.324 11.828 2.028 23.842 2.028 36.022zM576 198.408c91.934 18.662 169.544 76.742 214.45 155.826l184.978-60.102c-73.196-155.42-222.24-268.060-399.428-290.156v194.432zM233.55 354.232c44.906-79.084 122.516-137.164 214.45-155.826v-194.43c-177.188 22.096-326.23 134.736-399.426 290.154l184.976 60.102zM644.556 803.328c-40.39 18.408-85.272 28.672-132.556 28.672s-92.166-10.264-132.554-28.67l-114.292 157.31c73.206 40.366 157.336 63.36 246.846 63.36s173.64-22.994 246.848-63.36l-114.292-157.312z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["spinner","loading","loading-wheel","busy","wait"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":11,"prevSize":32,"code":59731,"name":"spinner"},"setIdx":4,"setId":1,"iconIdx":24},{"icon":{"paths":["M658.744 749.256l-210.744-210.746v-282.51h128v229.49l173.256 173.254zM512 0c-282.77 0-512 229.23-512 512s229.23 512 512 512 512-229.23 512-512-229.23-512-512-512zM512 896c-212.078 0-384-171.922-384-384s171.922-384 384-384c212.078 0 384 171.922 384 384s-171.922 384-384 384z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["clock","time","schedule"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":12,"prevSize":32,"code":59728,"name":"clock"},"setIdx":4,"setId":1,"iconIdx":25},{"icon":{"paths":["M128 320v640c0 35.2 28.8 64 64 64h576c35.2 0 64-28.8 64-64v-640h-704zM320 896h-64v-448h64v448zM448 896h-64v-448h64v448zM576 896h-64v-448h64v448zM704 896h-64v-448h64v448z","M848 128h-208v-80c0-26.4-21.6-48-48-48h-224c-26.4 0-48 21.6-48 48v80h-208c-26.4 0-48 21.6-48 48v80h832v-80c0-26.4-21.6-48-48-48zM576 128h-192v-63.198h192v63.198z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["bin","trashcan","remove","delete","recycle","dispose"],"grid":16},"attrs":[{},{}],"properties":{"order":1,"id":13,"name":"bin2","prevSize":32,"code":59650},"setIdx":4,"setId":1,"iconIdx":26},{"icon":{"paths":["M512 0c-282.77 0-512 229.23-512 512s229.23 512 512 512 512-229.23 512-512-229.23-512-512-512zM512 960.002c-62.958 0-122.872-13.012-177.23-36.452l233.148-262.29c5.206-5.858 8.082-13.422 8.082-21.26v-96c0-17.674-14.326-32-32-32-112.99 0-232.204-117.462-233.374-118.626-6-6.002-14.14-9.374-22.626-9.374h-128c-17.672 0-32 14.328-32 32v192c0 12.122 6.848 23.202 17.69 28.622l110.31 55.156v187.886c-116.052-80.956-192-215.432-192-367.664 0-68.714 15.49-133.806 43.138-192h116.862c8.488 0 16.626-3.372 22.628-9.372l128-128c6-6.002 9.372-14.14 9.372-22.628v-77.412c40.562-12.074 83.518-18.588 128-18.588 70.406 0 137.004 16.26 196.282 45.2-4.144 3.502-8.176 7.164-12.046 11.036-36.266 36.264-56.236 84.478-56.236 135.764s19.97 99.5 56.236 135.764c36.434 36.432 85.218 56.264 135.634 56.26 3.166 0 6.342-0.080 9.518-0.236 13.814 51.802 38.752 186.656-8.404 372.334-0.444 1.744-0.696 3.488-0.842 5.224-81.324 83.080-194.7 134.656-320.142 134.656z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["earth","globe","language","web","internet","sphere","planet"],"defaultCode":59850,"grid":16},"attrs":[],"properties":{"ligatures":"earth, globe2","name":"earth","id":14,"order":91,"prevSize":32,"code":59850},"setIdx":4,"setId":1,"iconIdx":27},{"icon":{"paths":["M512.002 193.212v-65.212h128v-64c0-35.346-28.654-64-64.002-64h-191.998c-35.346 0-64 28.654-64 64v64h128v65.212c-214.798 16.338-384 195.802-384 414.788 0 229.75 186.25 416 416 416s416-186.25 416-416c0-218.984-169.202-398.448-384-414.788zM706.276 834.274c-60.442 60.44-140.798 93.726-226.274 93.726s-165.834-33.286-226.274-93.726c-60.44-60.44-93.726-140.8-93.726-226.274s33.286-165.834 93.726-226.274c58.040-58.038 134.448-91.018 216.114-93.548l-21.678 314.020c-1.86 26.29 12.464 37.802 31.836 37.802s33.698-11.512 31.836-37.802l-21.676-314.022c81.666 2.532 158.076 35.512 216.116 93.55 60.44 60.44 93.726 140.8 93.726 226.274s-33.286 165.834-93.726 226.274z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["stopwatch","time","speed","meter","chronometer"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":15,"prevSize":32,"code":59715,"name":"elapsed"},"setIdx":4,"setId":1,"iconIdx":28},{"icon":{"paths":["M522.2 438.8v175.6h290.4c-11.8 75.4-87.8 220.8-290.4 220.8-174.8 0-317.4-144.8-317.4-323.2s142.6-323.2 317.4-323.2c99.4 0 166 42.4 204 79l139-133.8c-89.2-83.6-204.8-134-343-134-283 0-512 229-512 512s229 512 512 512c295.4 0 491.6-207.8 491.6-500.2 0-33.6-3.6-59.2-8-84.8l-483.6-0.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["google","brand"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":16,"prevSize":32,"code":59707,"name":"google"},"setIdx":4,"setId":1,"iconIdx":29},{"icon":{"paths":["M592 448h-16v-192c0-105.87-86.13-192-192-192h-128c-105.87 0-192 86.13-192 192v192h-16c-26.4 0-48 21.6-48 48v480c0 26.4 21.6 48 48 48h544c26.4 0 48-21.6 48-48v-480c0-26.4-21.6-48-48-48zM192 256c0-35.29 28.71-64 64-64h128c35.29 0 64 28.71 64 64v192h-256v-192z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lock","secure","private","encrypted"],"grid":16},"attrs":[{}],"properties":{"order":2,"id":17,"prevSize":32,"code":59700,"name":"lock"},"setIdx":4,"setId":1,"iconIdx":30},{"icon":{"paths":["M0.35 512l-0.35-312.074 384-52.144v364.218zM448 138.482l511.872-74.482v448h-511.872zM959.998 576l-0.126 448-511.872-72.016v-375.984zM384 943.836l-383.688-52.594-0.020-315.242h383.708z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["windows8","brand","os"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":18,"prevSize":32,"code":59712,"name":"microsoft"},"setIdx":4,"setId":1,"iconIdx":31},{"icon":{"paths":["M128 128h320v768h-320zM576 128h320v768h-320z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["pause","player"],"grid":16},"attrs":[{}],"properties":{"order":2,"id":19,"prevSize":32,"code":59695,"name":"pause"},"setIdx":4,"setId":1,"iconIdx":32},{"icon":{"paths":["M192 128l640 384-640 384z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["play","player"],"grid":16},"attrs":[{}],"properties":{"order":3,"id":20,"prevSize":32,"code":59696,"name":"play"},"setIdx":4,"setId":1,"iconIdx":33},{"icon":{"paths":["M889.68 166.32c-93.608-102.216-228.154-166.32-377.68-166.32-282.77 0-512 229.23-512 512h96c0-229.75 186.25-416 416-416 123.020 0 233.542 53.418 309.696 138.306l-149.696 149.694h352v-352l-134.32 134.32z","M928 512c0 229.75-186.25 416-416 416-123.020 0-233.542-53.418-309.694-138.306l149.694-149.694h-352v352l134.32-134.32c93.608 102.216 228.154 166.32 377.68 166.32 282.77 0 512-229.23 512-512h-96z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["loop","repeat","player","reload","refresh","update","synchronize","arrows"],"grid":16},"attrs":[{},{}],"properties":{"order":49,"id":21,"prevSize":32,"code":59694,"name":"reset"},"setIdx":4,"setId":1,"iconIdx":34},{"icon":{"paths":["M933.79 610.25c-53.726-93.054-21.416-212.304 72.152-266.488l-100.626-174.292c-28.75 16.854-62.176 26.518-97.846 26.518-107.536 0-194.708-87.746-194.708-195.99h-201.258c0.266 33.41-8.074 67.282-25.958 98.252-53.724 93.056-173.156 124.702-266.862 70.758l-100.624 174.292c28.97 16.472 54.050 40.588 71.886 71.478 53.638 92.908 21.512 211.92-71.708 266.224l100.626 174.292c28.65-16.696 61.916-26.254 97.4-26.254 107.196 0 194.144 87.192 194.7 194.958h201.254c-0.086-33.074 8.272-66.57 25.966-97.218 53.636-92.906 172.776-124.594 266.414-71.012l100.626-174.29c-28.78-16.466-53.692-40.498-71.434-71.228zM512 719.332c-114.508 0-207.336-92.824-207.336-207.334 0-114.508 92.826-207.334 207.336-207.334 114.508 0 207.332 92.826 207.332 207.334-0.002 114.51-92.824 207.334-207.332 207.334z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["cog","gear","preferences","settings","generate","control","options"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":22,"prevSize":32,"code":59693,"name":"settings2"},"setIdx":4,"setId":1,"iconIdx":35},{"icon":{"paths":["M512 128c-247.424 0-448 200.576-448 448s200.576 448 448 448 448-200.576 448-448-200.576-448-448-448zM512 936c-198.824 0-360-161.178-360-360 0-198.824 161.176-360 360-360 198.822 0 360 161.176 360 360 0 198.822-161.178 360-360 360zM934.784 287.174c16.042-28.052 25.216-60.542 25.216-95.174 0-106.040-85.96-192-192-192-61.818 0-116.802 29.222-151.92 74.596 131.884 27.236 245.206 105.198 318.704 212.578v0zM407.92 74.596c-35.116-45.374-90.102-74.596-151.92-74.596-106.040 0-192 85.96-192 192 0 34.632 9.174 67.122 25.216 95.174 73.5-107.38 186.822-185.342 318.704-212.578z","M512 576v-256h-64v320h256v-64z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["alarm","time","clock"],"grid":16},"attrs":[{},{}],"properties":{"order":2,"id":23,"prevSize":32,"code":59716,"name":"timeout"},"setIdx":4,"setId":1,"iconIdx":36},{"icon":{"paths":["M768 64c105.87 0 192 86.13 192 192v192h-128v-192c0-35.29-28.71-64-64-64h-128c-35.29 0-64 28.71-64 64v192h16c26.4 0 48 21.6 48 48v480c0 26.4-21.6 48-48 48h-544c-26.4 0-48-21.6-48-48v-480c0-26.4 21.6-48 48-48h400v-192c0-105.87 86.13-192 192-192h128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["unlocked","lock-open"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":24,"prevSize":32,"code":59699,"name":"unlocked"},"setIdx":4,"setId":1,"iconIdx":37},{"icon":{"paths":["M832 416h-320v64h-64v-96h384v-192h-32v96c0 17.664-14.336 32-32 32h-576c-17.696 0-32-14.336-32-32v-128c0-17.696 14.304-32 32-32h576c17.664 0 32 14.304 32 32h64v256h-32zM736 160h-512v32h512v-32zM544 832c0 35.328-28.672 64-64 64s-64-28.672-64-64v-320h128v320zM480 786.656c-17.696 0-32 14.336-32 32 0 17.696 14.304 32 32 32 17.664 0 32-14.304 32-32 0-17.664-14.336-32-32-32z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["paint","tool"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":32,"code":59725,"name":"control-Color"},"setIdx":4,"setId":1,"iconIdx":82},{"icon":{"paths":["M1328 320c-8.832 0-16 7.168-16 16v640c0 8.832-7.168 16-16 16h-1248c-8.832 0-16-7.168-16-16v-640c0-8.832-7.168-16-16-16s-16 7.168-16 16v640c0 26.464 21.536 48 48 48h1248c26.464 0 48-21.536 48-48v-640c0-8.832-7.168-16-16-16zM1296 0h-1248c-26.464 0-48 21.536-48 48v192c0 8.832 7.168 16 16 16h1312c8.832 0 16-7.168 16-16v-192c0-26.464-21.536-48-48-48zM1312 224h-1280v-176c0-8.832 7.168-16 16-16h1248c8.832 0 16 7.168 16 16v176zM560 896c8.832 0 16-7.168 16-16v-512c0-8.832-7.168-16-16-16h-416c-8.832 0-16 7.168-16 16v512c0 8.832 7.168 16 16 16h416zM160 384h384v480h-384v-480zM720 480h480c8.832 0 16-7.168 16-16s-7.168-16-16-16h-480c-8.832 0-16 7.168-16 16s7.168 16 16 16zM720 640h480c8.832 0 16-7.168 16-16s-7.168-16-16-16h-480c-8.832 0-16 7.168-16 16s7.168 16 16 16zM720 800h480c8.832 0 16-7.168 16-16s-7.168-16-16-16h-480c-8.832 0-16 7.168-16 16s7.168 16 16 16zM96 128c0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32s-32 14.327-32 32zM224 128c0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32s-32 14.327-32 32zM352 128c0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32s-32 14.327-32 32z"],"width":1344,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["browser","window","software","program"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":32,"code":59701,"name":"browser"},"setIdx":4,"setId":1,"iconIdx":83},{"icon":{"paths":["M927.936 272.992l-68.288-68.288c-12.608-12.576-32.96-12.576-45.536 0l-409.44 409.44-194.752-196.16c-12.576-12.576-32.928-12.576-45.536 0l-68.288 68.288c-12.576 12.608-12.576 32.96 0 45.536l285.568 287.488c12.576 12.576 32.96 12.576 45.536 0l500.736-500.768c12.576-12.544 12.576-32.96 0-45.536z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["checkmark","tick","approve","submit"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":2,"prevSize":32,"code":59714,"name":"checkmark"},"setIdx":4,"setId":1,"iconIdx":84},{"icon":{"paths":["M1020.192 401.824c-8.864-25.568-31.616-44.288-59.008-48.352l-266.432-39.616-115.808-240.448c-12.192-25.248-38.272-41.408-66.944-41.408s-54.752 16.16-66.944 41.408l-115.808 240.448-266.464 39.616c-27.36 4.064-50.112 22.784-58.944 48.352-8.8 25.632-2.144 53.856 17.184 73.12l195.264 194.944-45.28 270.432c-4.608 27.232 7.2 54.56 30.336 70.496 12.704 8.736 27.648 13.184 42.592 13.184 12.288 0 24.608-3.008 35.776-8.992l232.288-125.056 232.32 125.056c11.168 5.984 23.488 8.992 35.744 8.992 14.944 0 29.888-4.448 42.624-13.184 23.136-15.936 34.88-43.264 30.304-70.496l-45.312-270.432 195.328-194.944c19.296-19.296 25.92-47.52 17.184-73.12zM754.816 619.616c-16.384 16.32-23.808 39.328-20.064 61.888l45.312 270.432-232.32-124.992c-11.136-6.016-23.424-8.992-35.776-8.992-12.288 0-24.608 3.008-35.744 8.992l-232.32 124.992 45.312-270.432c3.776-22.56-3.648-45.568-20.032-61.888l-195.264-194.944 266.432-39.68c24.352-3.616 45.312-18.848 55.776-40.576l115.872-240.384 115.84 240.416c10.496 21.728 31.424 36.928 55.744 40.576l266.496 39.68-195.264 194.912z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["star","favorite"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":3,"prevSize":32,"code":59706,"name":"control-Stars"},"setIdx":4,"setId":1,"iconIdx":85},{"icon":{"paths":["M409.6 204.8h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2zM768 204.8h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2zM409.6 563.2h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2zM768 563.2h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["grid"],"grid":20},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":20,"code":59730,"name":"grid1"},"setIdx":4,"setId":1,"iconIdx":86},{"icon":{"paths":["M737.28 460.8h-296.96c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h296.96c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM839.68 716.8h-399.36c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h399.36c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM440.32 307.2h399.36c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2h-399.36c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2zM276.48 460.8h-92.16c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h92.16c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM276.48 716.8h-92.16c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h92.16c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM276.48 204.8h-92.16c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h92.16c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["list"],"grid":20},"attrs":[{}],"properties":{"order":1,"id":1,"name":"list","prevSize":20,"code":59726},"setIdx":4,"setId":1,"iconIdx":87},{"icon":{"paths":["M636.518 0c68.608 0 102.912 46.694 102.912 100.198 0 66.816-59.597 128.614-137.165 128.614-64.973 0-102.861-38.4-101.069-101.888 0-53.402 45.107-126.925 135.322-126.925zM425.421 1024c-54.17 0-93.85-33.382-55.962-180.429l62.157-260.71c10.803-41.677 12.595-58.419 0-58.419-16.23 0-86.477 28.774-128.102 57.19l-27.034-45.056c131.686-111.923 283.187-177.51 348.211-177.51 54.118 0 63.13 65.178 36.096 165.376l-71.219 274.022c-12.595 48.384-7.219 65.075 5.427 65.075 16.23 0 69.478-20.070 121.805-61.798l30.72 41.677c-128.102 130.406-268.032 180.582-322.099 180.582z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["info"],"grid":20},"attrs":[{}],"properties":{"order":1,"id":2,"prevSize":20,"code":59708,"name":"info"},"setIdx":4,"setId":1,"iconIdx":88},{"icon":{"paths":["M950.857 932.571v-621.714c0-9.714-8.571-18.286-18.286-18.286h-621.714c-9.714 0-18.286 8.571-18.286 18.286v621.714c0 9.714 8.571 18.286 18.286 18.286h621.714c9.714 0 18.286-8.571 18.286-18.286zM1024 310.857v621.714c0 50.286-41.143 91.429-91.429 91.429h-621.714c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h621.714c50.286 0 91.429 41.143 91.429 91.429zM804.571 91.429v91.429h-73.143v-91.429c0-9.714-8.571-18.286-18.286-18.286h-621.714c-9.714 0-18.286 8.571-18.286 18.286v621.714c0 9.714 8.571 18.286 18.286 18.286h91.429v73.143h-91.429c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h621.714c50.286 0 91.429 41.143 91.429 91.429z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["clone"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":28,"code":59754,"name":"clone"},"setIdx":4,"setId":1,"iconIdx":89},{"icon":{"paths":["M498.787 330.323v-49.548h112.31v-66.065c0-49.548-39.639-89.187-89.187-89.187s-89.187 39.639-89.187 89.187v541.729l89.187 161.858 89.187-161.858v-426.116z","M360.052 716.8h-66.065c-59.458 0-105.703-46.245-105.703-105.703v-254.348c0-59.458 46.245-105.703 105.703-105.703h66.065v-42.942h-66.065c-82.581 0-148.645 66.065-148.645 148.645v254.348c0 82.581 66.065 148.645 148.645 148.645h66.065z","M852.232 260.955c-26.426-33.032-66.065-52.852-109.006-52.852h-59.458v42.942h39.639c42.942 0 82.581 19.819 109.006 52.852l145.342 181.677-142.039 178.374c-26.426 33.032-69.368 52.852-112.31 52.852h-36.335v42.942h56.155c42.942 0 85.884-19.819 112.31-52.852l178.374-221.316z"],"width":1140,"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Tags"],"grid":14},"attrs":[{},{},{}],"properties":{"order":119,"id":1,"name":"control-Tags","prevSize":28,"code":59747},"setIdx":4,"setId":1,"iconIdx":90},{"icon":{"paths":["M384 179.2h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6zM998.4 486.4h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6zM998.4 844.8h-614.4c-38.406 15.539-22.811 37.543 0 51.2h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6z","M0 0v307.2h307.2v-307.2zM47.4 47.4h212.4v212.4h-212.4z","M0 716.8v307.2h307.2v-307.2zM47.4 764.2h212.4v212.4h-212.4z","M0 358.4v307.2h307.2v-307.2zM47.4 405.8h212.4v212.4h-212.4z","M89.6 89.6h128v128h-128v-128z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Checkboxes"],"grid":14},"attrs":[{},{},{},{},{}],"properties":{"order":118,"id":2,"name":"control-Checkboxes","prevSize":28,"code":59746},"setIdx":4,"setId":1,"iconIdx":91},{"icon":{"paths":["M159.073 665.6l-159.073-134.055 159.073-133.819 36.818 37.29-117.062 96.057 117.062 97.237z","M493.247 536.029q0 33.042-9.441 57.115-9.205 24.073-25.961 40.122-16.521 15.813-39.178 23.601-22.657 7.552-49.327 7.552-26.197 0-48.855-4.012-22.421-3.776-42.954-10.385v-323.338h57.587v78.356l-2.36 47.203q12.981-16.757 30.21-26.905 17.465-10.149 41.774-10.149 21.241 0 37.762 8.496t27.614 24.309q11.329 15.577 17.229 37.998 5.9 22.185 5.9 50.035zM432.828 538.389q0-19.825-2.832-33.75t-8.26-22.893q-5.192-8.969-12.981-12.981-7.552-4.248-17.465-4.248-14.633 0-28.086 11.801-13.217 11.801-28.086 32.098v104.79q6.844 2.596 16.757 4.248 10.149 1.652 20.533 1.652 13.689 0 24.781-5.664 11.329-5.664 19.117-16.049 8.024-10.385 12.273-25.253 4.248-15.105 4.248-33.75z","M700.682 513.608q0.472-13.453-1.416-22.893-1.652-9.441-5.664-15.577-3.776-6.136-9.441-8.968t-12.981-2.832q-12.745 0-26.433 10.621-13.453 10.385-29.738 34.458v151.756h-59.003v-239.789h52.159l2.124 34.93q5.9-9.205 13.217-16.521 7.552-7.316 16.521-12.509 9.205-5.428 20.297-8.26t24.309-2.832q18.173 0 32.098 6.372 14.161 6.136 23.601 18.409 9.677 12.273 14.161 30.918 4.72 18.409 4.012 42.718z","M864.927 397.725l159.073 133.819-159.073 134.055-36.582-37.29 116.826-96.293-116.826-97.001z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Html"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":116,"id":3,"name":"control-Html","prevSize":28,"code":59744},"setIdx":4,"setId":1,"iconIdx":92},{"icon":{"paths":["M251.429 100.58c-87.896 0-160 72.104-160 160v525.714c0 87.896 72.104 160 160 160h525.714c87.896 0 160-72.104 160-160v-525.714c0-87.896-72.104-160-160-160zM251.429 146.295h525.714c62.961 0 114.286 51.325 114.286 114.286v525.714c0 62.961-51.325 114.286-114.286 114.286h-525.714c-62.961 0-114.286-51.325-114.286-114.286v-525.714c0-62.961 51.325-114.286 114.286-114.286z","M251.429 306.295c-0.096-0.001-0.21-0.002-0.323-0.002-12.625 0-22.859 10.235-22.859 22.859s10.235 22.859 22.859 22.859c0.114 0 0.227-0.001 0.34-0.002l-0.017 0h525.714c0.096 0.001 0.21 0.002 0.323 0.002 12.625 0 22.859-10.235 22.859-22.859s-10.235-22.859-22.859-22.859c-0.114 0-0.227 0.001-0.34 0.002l0.017-0z","M251.429 443.438c-0.096-0.001-0.21-0.002-0.323-0.002-12.625 0-22.859 10.235-22.859 22.859s10.235 22.859 22.859 22.859c0.114 0 0.227-0.001 0.34-0.002l-0.017 0h297.143c0.096 0.001 0.21 0.002 0.323 0.002 12.625 0 22.859-10.235 22.859-22.859s-10.235-22.859-22.859-22.859c-0.114 0-0.227 0.001-0.34 0.002l0.017-0z","M251.429 580.58c-0.096-0.001-0.21-0.002-0.323-0.002-12.625 0-22.859 10.235-22.859 22.859s10.235 22.859 22.859 22.859c0.114 0 0.227-0.001 0.34-0.002l-0.017 0h297.143c0.096 0.001 0.21 0.002 0.323 0.002 12.625 0 22.859-10.235 22.859-22.859s-10.235-22.859-22.859-22.859c-0.114 0-0.227 0.001-0.34 0.002l0.017-0z"],"width":1029,"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["single-content"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":112,"id":4,"name":"single-content","prevSize":28,"code":59736},"setIdx":4,"setId":1,"iconIdx":93},{"icon":{"paths":["M777.143 946.286h-525.714c-89.143 0-160-70.857-160-160v-297.143c0-89.143 70.857-160 160-160h525.714c89.143 0 160 70.857 160 160v297.143c0 89.143-70.857 160-160 160zM251.429 374.857c-64 0-114.286 50.286-114.286 114.286v297.143c0 64 50.286 114.286 114.286 114.286h525.714c64 0 114.286-50.286 114.286-114.286v-297.143c0-64-50.286-114.286-114.286-114.286h-525.714z","M731.429 580.571h-457.143c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h457.143c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z","M502.857 740.571h-228.571c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h228.571c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z","M777.143 260.571h-525.714c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h525.714c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z","M685.714 146.286h-342.857c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h342.857c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z"],"width":1029,"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["multiple-content"],"grid":14},"attrs":[{},{},{},{},{}],"properties":{"order":113,"id":5,"name":"multiple-content","prevSize":28,"code":59735},"setIdx":4,"setId":1,"iconIdx":94},{"icon":{"paths":["M832 268.8h-657.92c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h657.92c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z","M832 453.12h-409.6c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h409.6c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z","M832 642.56h-409.6c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h409.6c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z","M832 832h-409.6c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h409.6c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-Array"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":108,"id":6,"name":"type-Array","prevSize":28,"code":59734},"setIdx":4,"setId":1,"iconIdx":95},{"icon":{"paths":["M292.571 713.143v128c0 20-16.571 36.571-36.571 36.571h-146.286c-20 0-36.571-16.571-36.571-36.571v-128c0-20 16.571-36.571 36.571-36.571h146.286c20 0 36.571 16.571 36.571 36.571zM309.714 109.714l-16 438.857c-0.571 20-17.714 36.571-37.714 36.571h-146.286c-20 0-37.143-16.571-37.714-36.571l-16-438.857c-0.571-20 15.429-36.571 35.429-36.571h182.857c20 0 36 16.571 35.429 36.571z"],"width":366,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["exclamation"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":7,"prevSize":28,"code":59733,"name":"exclamation"},"setIdx":4,"setId":1,"iconIdx":96},{"icon":{"paths":["M512 26.38l-424.96 242.8v485.64l424.96 242.8 424.96-242.8v-485.64l-424.96-242.8zM512 235.52l245.76 138.24v276.48l-245.76 138.24-245.76-138.24v-276.48l245.76-138.24z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["orleans"],"grid":14},"attrs":[{}],"properties":{"order":99,"id":8,"name":"orleans","prevSize":28,"code":59723},"setIdx":4,"setId":1,"iconIdx":97},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v204.8h51.2v-204.8h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-307.2v51.2h307.2c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM716.8 189.8l117.4 117.4h-117.4z","M153.6 640v281.6h358.4v-281.6zM179.2 640v-76.8c0-84.48 69.12-153.6 153.6-153.6s153.6 69.12 153.6 153.6v76.8h-51.2v-76.8c0-56.32-46.080-102.4-102.4-102.4s-102.4 46.080-102.4 102.4v76.8z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-lock"],"grid":14},"attrs":[{},{}],"properties":{"order":97,"id":9,"name":"document-lock","prevSize":28,"code":59721},"setIdx":4,"setId":1,"iconIdx":98},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v153.6h51.2v-153.6h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM716.8 189.8l117.4 117.4h-117.4zM332.8 460.8l-230.4 256v51.2h102.4v153.6h256v-153.6h102.4v-51.2zM332.8 537.3l161.5 179.5h-84.7v153.6h-153.6v-153.6h-84.7z","M102.4 357.532h460.8v52.068h-460.8v-52.068z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-unpublish"],"grid":14},"attrs":[{},{}],"properties":{"order":96,"id":10,"name":"document-unpublish","prevSize":28,"code":59711},"setIdx":4,"setId":1,"iconIdx":99},{"icon":{"paths":["M614.286 420.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-down"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":11,"prevSize":28,"code":59648,"name":"angle-down"},"setIdx":4,"setId":1,"iconIdx":100},{"icon":{"paths":["M358.286 310.857c0 4.571-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8 5.714 13.143z"],"width":384,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-left"],"grid":14},"attrs":[{}],"properties":{"order":2,"id":12,"prevSize":28,"code":59649,"name":"angle-left"},"setIdx":4,"setId":1,"iconIdx":101},{"icon":{"paths":["M340 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8-5.714-13.143 0-4.571 2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":347,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-right"],"grid":14},"attrs":[{}],"properties":{"order":67,"id":13,"prevSize":28,"code":59697,"name":"angle-right"},"setIdx":4,"setId":1,"iconIdx":102},{"icon":{"paths":["M614.286 676.571c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-up"],"grid":14},"attrs":[{}],"properties":{"order":2,"id":14,"prevSize":28,"code":59651,"name":"angle-up"},"setIdx":4,"setId":1,"iconIdx":103},{"icon":{"paths":["M592 393.6h-156.8c-57.6 0-105.6-48-105.6-105.6v-182.4c0-57.6 48-105.6 105.6-105.6h156.8c57.6 0 105.6 48 105.6 105.6v182.4c-3.2 57.6-48 105.6-105.6 105.6zM432 64c-22.4 0-41.6 19.2-41.6 41.6v182.4c0 22.4 19.2 41.6 41.6 41.6h156.8c22.4 0 41.6-19.2 41.6-41.6v-182.4c0-22.4-19.2-41.6-41.6-41.6h-156.8z","M195.2 1024c-105.6 0-195.2-89.6-195.2-195.2 0-108.8 89.6-195.2 195.2-195.2s195.2 89.6 195.2 195.2c3.2 105.6-86.4 195.2-195.2 195.2zM195.2 694.4c-73.6 0-131.2 60.8-131.2 131.2 0 73.6 60.8 134.4 131.2 134.4 73.6 0 131.2-60.8 131.2-131.2 3.2-73.6-57.6-134.4-131.2-134.4z","M828.8 1024c-108.8 0-195.2-89.6-195.2-195.2 0-108.8 89.6-195.2 195.2-195.2s195.2 89.6 195.2 195.2c0 105.6-89.6 195.2-195.2 195.2zM828.8 694.4c-73.6 0-131.2 60.8-131.2 131.2 0 73.6 60.8 131.2 131.2 131.2 73.6 0 131.2-60.8 131.2-131.2s-60.8-131.2-131.2-131.2z","M332.8 640c-6.4 0-12.8 0-16-3.2-16-9.6-19.2-28.8-9.6-44.8l83.2-137.6c9.6-16 28.8-19.2 44.8-9.6s19.2 28.8 9.6 44.8l-83.2 137.6c-6.4 6.4-16 12.8-28.8 12.8z","M691.2 640c-9.6 0-22.4-6.4-28.8-16l-83.2-137.6c-9.6-16-3.2-35.2 9.6-44.8s35.2-3.2 44.8 9.6l83.2 137.6c9.6 16 3.2 35.2-9.6 44.8-6.4 6.4-12.8 6.4-16 6.4z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["api"],"grid":14},"attrs":[{},{},{},{},{}],"properties":{"order":94,"id":15,"name":"api","prevSize":28,"code":59717},"setIdx":4,"setId":1,"iconIdx":104},{"icon":{"paths":["M800 1024h-576c-124.8 0-224-99.2-224-224v-576c0-124.8 99.2-224 224-224h576c124.8 0 224 99.2 224 224v576c0 124.8-99.2 224-224 224zM224 64c-89.6 0-160 70.4-160 160v576c0 89.6 70.4 160 160 160h576c89.6 0 160-70.4 160-160v-576c0-89.6-70.4-160-160-160h-576z","M771.2 860.8h-438.4c-12.8 0-22.4-6.4-28.8-19.2s-3.2-25.6 3.2-35.2l300.8-355.2c6.4-6.4 16-12.8 25.6-12.8s19.2 6.4 25.6 12.8l192 275.2c3.2 3.2 3.2 6.4 3.2 9.6 16 44.8 3.2 73.6-6.4 89.6-22.4 32-70.4 35.2-76.8 35.2zM403.2 796.8h371.2c6.4 0 22.4-3.2 25.6-9.6 3.2-3.2 3.2-12.8 0-25.6l-166.4-236.8-230.4 272z","M332.8 502.4c-76.8 0-140.8-64-140.8-140.8s64-140.8 140.8-140.8 140.8 64 140.8 140.8-60.8 140.8-140.8 140.8zM332.8 284.8c-41.6 0-76.8 32-76.8 76.8s35.2 76.8 76.8 76.8 76.8-35.2 76.8-76.8-32-76.8-76.8-76.8z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["assets"],"grid":14},"attrs":[{},{},{}],"properties":{"order":95,"id":16,"name":"assets","prevSize":28,"code":59720},"setIdx":4,"setId":1,"iconIdx":105},{"icon":{"paths":["M932.571 548.571c0 20-16.571 36.571-36.571 36.571h-128c0 71.429-15.429 125.143-38.286 165.714l118.857 119.429c14.286 14.286 14.286 37.143 0 51.429-6.857 7.429-16.571 10.857-25.714 10.857s-18.857-3.429-25.714-10.857l-113.143-112.571s-74.857 68.571-172 68.571v-512h-73.143v512c-103.429 0-178.857-75.429-178.857-75.429l-104.571 118.286c-7.429 8-17.143 12-27.429 12-8.571 0-17.143-2.857-24.571-9.143-14.857-13.714-16-36.571-2.857-52l115.429-129.714c-20-39.429-33.143-90.286-33.143-156.571h-128c-20 0-36.571-16.571-36.571-36.571s16.571-36.571 36.571-36.571h128v-168l-98.857-98.857c-14.286-14.286-14.286-37.143 0-51.429s37.143-14.286 51.429 0l98.857 98.857h482.286l98.857-98.857c14.286-14.286 37.143-14.286 51.429 0s14.286 37.143 0 51.429l-98.857 98.857v168h128c20 0 36.571 16.571 36.571 36.571zM658.286 219.429h-365.714c0-101.143 81.714-182.857 182.857-182.857s182.857 81.714 182.857 182.857z"],"width":951,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["bug"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":17,"prevSize":28,"code":59709,"name":"bug"},"setIdx":4,"setId":1,"iconIdx":106},{"icon":{"paths":["M585.143 402.286c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"],"width":585,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-down"],"grid":14},"attrs":[{}],"properties":{"order":4,"id":18,"prevSize":28,"code":59692,"name":"caret-down"},"setIdx":4,"setId":1,"iconIdx":107},{"icon":{"paths":["M365.714 256v512c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":402,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-left"],"grid":14},"attrs":[{}],"properties":{"order":2,"id":19,"prevSize":28,"code":59690,"name":"caret-left"},"setIdx":4,"setId":1,"iconIdx":108},{"icon":{"paths":["M329.143 512c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-512c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":329,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-right"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":20,"prevSize":28,"code":59689,"name":"caret-right"},"setIdx":4,"setId":1,"iconIdx":109},{"icon":{"paths":["M585.143 694.857c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-up"],"grid":14},"attrs":[{}],"properties":{"order":3,"id":21,"prevSize":28,"code":59691,"name":"caret-up"},"setIdx":4,"setId":1,"iconIdx":110},{"icon":{"paths":["M800 1024h-576c-124.8 0-224-99.2-224-224v-576c0-124.8 99.2-224 224-224h576c124.8 0 224 99.2 224 224v576c0 124.8-99.2 224-224 224zM224 64c-89.6 0-160 70.4-160 160v576c0 89.6 70.4 160 160 160h576c89.6 0 160-70.4 160-160v-576c0-89.6-70.4-160-160-160h-576z","M480 448h-211.2c-57.6 0-105.6-48-105.6-105.6v-73.6c0-57.6 48-105.6 105.6-105.6h211.2c57.6 0 105.6 48 105.6 105.6v73.6c0 57.6-48 105.6-105.6 105.6zM268.8 227.2c-22.4 0-41.6 19.2-41.6 41.6v73.6c0 22.4 19.2 41.6 41.6 41.6h211.2c22.4 0 41.6-19.2 41.6-41.6v-73.6c0-22.4-19.2-41.6-41.6-41.6h-211.2z","M828.8 611.2h-633.6c-19.2 0-32-12.8-32-32s12.8-32 32-32h630.4c19.2 0 32 12.8 32 32s-12.8 32-28.8 32z","M553.6 777.6h-358.4c-19.2 0-32-12.8-32-32s12.8-32 32-32h355.2c19.2 0 32 12.8 32 32s-12.8 32-28.8 32z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["content"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":93,"id":22,"name":"contents, trigger-ContentChanged","prevSize":28,"code":59718},"setIdx":4,"setId":1,"iconIdx":111},{"icon":{"paths":["M947.2 102.4h-128v-25.6c0-14.131-11.469-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-512v-25.6c0-14.131-11.52-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-128c-42.342 0-76.8 34.458-76.8 76.8v716.8c0 42.342 34.458 76.8 76.8 76.8h870.4c42.342 0 76.8-34.458 76.8-76.8v-716.8c0-42.342-34.458-76.8-76.8-76.8zM972.8 896c0 14.131-11.469 25.6-25.6 25.6h-870.4c-14.080 0-25.6-11.469-25.6-25.6v-537.6h921.6v537.6zM972.8 307.2h-921.6v-128c0-14.080 11.52-25.6 25.6-25.6h128v76.8c0 14.080 11.52 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h512v76.8c0 14.080 11.469 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h128c14.131 0 25.6 11.52 25.6 25.6v128zM332.8 512h51.2c14.080 0 25.6-11.52 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM640 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-date"],"grid":14},"attrs":[{}],"properties":{"order":71,"id":23,"name":"control-Date","prevSize":28,"code":59702},"setIdx":4,"setId":1,"iconIdx":112},{"icon":{"paths":["M486.4 409.6h51.2c14.080 0 25.6 11.52 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.52-25.6-25.6s11.52-25.6 25.6-25.6zM230.4 614.4c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM230.4 512c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM51.2 742.4v-435.2h665.6v102.4h51.2v-281.6c0-42.342-34.458-76.8-76.8-76.8h-128v-25.6c0-14.131-11.469-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-256v-25.6c0-14.131-11.52-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-128c-42.342 0-76.8 34.458-76.8 76.8v614.4c0 42.342 34.458 76.8 76.8 76.8h332.8v-51.2h-332.8c-14.080 0-25.6-11.469-25.6-25.6zM51.2 128c0-14.080 11.52-25.6 25.6-25.6h128v76.8c0 14.080 11.52 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h256v76.8c0 14.080 11.469 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h128c14.131 0 25.6 11.52 25.6 25.6v128h-665.6v-128zM384 409.6c14.080 0 25.6 11.52 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.52-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM742.4 460.8c-155.546 0-281.6 126.054-281.6 281.6s126.054 281.6 281.6 281.6 281.6-126.054 281.6-281.6-126.054-281.6-281.6-281.6zM742.4 972.8c-127.232 0-230.4-103.168-230.4-230.4s103.168-230.4 230.4-230.4 230.4 103.168 230.4 230.4-103.168 230.4-230.4 230.4zM384 512c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM384 614.4c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM844.8 716.8c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-102.4c-14.131 0-25.6-11.469-25.6-25.6v-102.4c0-14.131 11.469-25.6 25.6-25.6s25.6 11.469 25.6 25.6v76.8h76.8z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-date-time"],"grid":14},"attrs":[{}],"properties":{"order":70,"id":24,"name":"control-DateTime","prevSize":28,"code":59703},"setIdx":4,"setId":1,"iconIdx":113},{"icon":{"paths":["M793.6 609.416h-61.838v-28.108h-0.783q-21.135 33.092-62.034 33.092-37.573 0-60.469-26.912-22.896-27.112-22.896-75.554 0-50.635 25.244-81.136t66.144-30.501q38.747 0 54.011 28.308h0.783v-121.405h61.838v302.216zM732.936 510.139v-15.35q0-19.935-11.35-33.092t-29.549-13.157q-20.548 0-32.093 16.546-11.546 16.347-11.546 45.053 0 26.912 11.154 41.465t30.919 14.553q18.786 0 30.528-15.35 11.937-15.35 11.937-40.668zM548.594 609.416h-61.643v-116.421q0-44.455-32.093-44.455-15.264 0-24.853 13.357t-9.589 33.292v114.228h-61.839v-117.617q0-43.259-31.506-43.259-15.851 0-25.44 12.758-9.393 12.758-9.393 34.687v113.431h-61.838v-204.135h61.838v31.896h0.783q9.589-16.347 26.81-26.514 17.417-10.366 37.964-10.366 42.465 0 58.12 38.076 22.896-38.076 67.318-38.076 65.361 0 65.361 82.133v126.987zM0 0v204.8h76.8v76.8h51.2v-76.8h76.8v-204.8zM819.2 0v204.8h204.8v-204.8zM51.2 51.2h102.4v102.4h-102.4zM870.4 51.2h102.4v102.4h-102.4zM281.6 76.8v51.2h102.4v-51.2zM486.4 76.8v51.2h102.4v-51.2zM691.2 76.8v51.2h102.4v-51.2zM896 281.6v102.4h51.2v-102.4zM76.8 384v102.4h51.2v-102.4zM896 486.4v102.4h51.2v-102.4zM76.8 588.8v102.4h51.2v-102.4zM896 691.2v102.4h51.2v-102.4zM76.8 793.6v25.6h-76.8v204.8h204.8v-76.8h76.8v-51.2h-76.8v-76.8h-76.8v-25.6zM819.2 819.2v76.8h-25.6v51.2h25.6v76.8h204.8v-204.8zM51.2 870.4h102.4v102.4h-102.4zM870.4 870.4h102.4v102.4h-102.4zM384 896v51.2h102.4v-51.2zM588.8 896v51.2h102.4v-51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Markdown"],"grid":14},"attrs":[{}],"properties":{"order":72,"id":25,"name":"control-Markdown","prevSize":28,"code":59704},"setIdx":4,"setId":1,"iconIdx":114},{"icon":{"paths":["M292.571 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["th"],"defaultCode":61450,"grid":14},"attrs":[],"properties":{"name":"grid","id":26,"order":83,"prevSize":28,"code":61450},"setIdx":4,"setId":1,"iconIdx":115},{"icon":{"paths":["M877.714 768v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 475.429v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 182.857v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["bars","navicon","reorder"],"defaultCode":61641,"grid":14},"attrs":[],"properties":{"name":"list1","id":27,"order":89,"prevSize":28,"code":61641},"setIdx":4,"setId":1,"iconIdx":116},{"icon":{"paths":["M512 64c-131.696 0-239.125 107.4-239.125 239 0 65.8 24.831 146.717 65.375 215.25 19.653 33.221 43.902 63.853 71.75 87.125-59.423 7.524-122.009 9.415-172.125 32-79.809 35.967-144.343 94.74-172.375 178.625-1.5 9.499 0 0-1.5 9v0.499c0 73.995 60.563 134.501 134.375 134.501h627.125c73.888 0 134.5-60.506 134.5-134.5l-1.5-9.375c-27.845-84.263-92.273-143.119-172.125-179-50.17-22.544-112.844-24.421-172.375-31.875 27.792-23.26 52.002-53.831 71.625-87 40.544-68.533 65.375-149.45 65.375-215.25 0-131.6-107.304-239-239-239zM512 124c99.241 0 179 79.875 179 179 0 49.562-21.877 125.381-57 184.75s-81.435 98.75-122 98.75c-40.565 0-86.877-39.381-122-98.75s-57.125-135.188-57.125-184.75c0-99.125 79.884-179 179.125-179zM512 646.5c92.551 0 180.829 14.406 249.75 45.375 66.784 30.009 113.649 74.724 136.5 137.75-2.447 39.259-32.9 70.375-72.75 70.375h-627.125c-39.678 0-70.116-31.051-72.625-70.25 22.978-62.705 69.953-107.523 136.75-137.625 68.937-31.067 157.205-45.625 249.5-45.625z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["user-o"],"grid":14},"attrs":[{}],"properties":{"order":64,"id":28,"name":"user-o","prevSize":28,"code":59698},"setIdx":4,"setId":1,"iconIdx":117},{"icon":{"paths":["M217.6 992c-3.2 0-3.2 0-6.4 0h-3.2c-144-25.6-208-144-208-249.6 0-99.2 57.6-208 185.6-240v-147.2c0-19.2 12.8-32 32-32s32 12.8 32 32v172.8c0 16-12.8 28.8-25.6 32-108.8 16-160 102.4-160 182.4s48 166.4 153.6 185.6h6.4c16 3.2 28.8 19.2 25.6 38.4-3.2 16-16 25.6-32 25.6z","M774.4 1001.6c0 0 0 0 0 0-102.4 0-211.2-60.8-243.2-185.6h-176c-19.2 0-32-12.8-32-32s12.8-32 32-32h201.6c16 0 28.8 12.8 32 25.6 16 108.8 102.4 156.8 182.4 160 80 0 166.4-48 185.6-153.6v-3.2c3.2-16 19.2-28.8 38.4-25.6 16 3.2 28.8 19.2 25.6 38.4v3.2c-22.4 140.8-140.8 204.8-246.4 204.8z","M787.2 678.4c-19.2 0-32-12.8-32-32v-176c0-16 12.8-28.8 25.6-32 108.8-16 156.8-102.4 160-182.4 0-80-48-166.4-153.6-185.6h-3.2c-19.2-6.4-32-22.4-28.8-38.4s19.2-28.8 38.4-25.6h3.2c144 25.6 208 144 208 249.6 0 99.2-60.8 208-185.6 240v150.4c0 16-16 32-32 32z","M41.6 246.4c-3.2 0-3.2 0-6.4 0-16-3.2-28.8-19.2-25.6-35.2v-3.2c25.6-144 140.8-208 246.4-208 0 0 3.2 0 3.2 0 99.2 0 208 60.8 240 185.6h147.2c19.2 0 32 12.8 32 32s-12.8 32-32 32h-172.8c-16 0-28.8-12.8-32-25.6-16-108.8-102.4-156.8-182.4-160-80 0-166.4 48-185.6 153.6v3.2c-3.2 16-16 25.6-32 25.6z","M256 387.2c-32 0-67.2-12.8-92.8-38.4-51.2-51.2-51.2-134.4 0-185.6 25.6-22.4 57.6-35.2 92.8-35.2s67.2 12.8 92.8 38.4c25.6 25.6 38.4 57.6 38.4 92.8s-12.8 67.2-38.4 92.8c-25.6 22.4-57.6 35.2-92.8 35.2zM256 192c-16 0-32 6.4-44.8 19.2-25.6 25.6-25.6 67.2 0 92.8s67.2 25.6 92.8 0c12.8-12.8 19.2-28.8 19.2-48s-6.4-32-19.2-44.8-28.8-19.2-48-19.2z","M771.2 873.6c-32 0-67.2-12.8-92.8-38.4-51.2-51.2-51.2-134.4 0-185.6 25.6-25.6 57.6-38.4 92.8-38.4s67.2 12.8 92.8 38.4c25.6 25.6 38.4 57.6 38.4 92.8s-12.8 67.2-38.4 92.8c-28.8 25.6-60.8 38.4-92.8 38.4zM771.2 678.4c-19.2 0-35.2 6.4-48 19.2-25.6 25.6-25.6 67.2 0 92.8s67.2 25.6 92.8 0c12.8-12.8 19.2-28.8 19.2-48s-6.4-35.2-19.2-48-28.8-16-44.8-16z","M745.6 387.2c-32 0-67.2-12.8-92.8-38.4s-38.4-57.6-38.4-92.8 12.8-67.2 38.4-92.8c25.6-22.4 60.8-35.2 92.8-35.2s67.2 12.8 92.8 38.4c51.2 51.2 51.2 134.4 0 185.6v0c-25.6 22.4-57.6 35.2-92.8 35.2zM745.6 192c-19.2 0-35.2 6.4-48 19.2s-19.2 28.8-19.2 48 6.4 35.2 19.2 48c25.6 25.6 67.2 25.6 92.8 0s25.6-67.2 0-92.8c-9.6-16-25.6-22.4-44.8-22.4z","M259.2 873.6c-32 0-67.2-12.8-92.8-38.4s-38.4-57.6-38.4-92.8 12.8-67.2 38.4-92.8c25.6-22.4 57.6-35.2 92.8-35.2s67.2 12.8 92.8 38.4c51.2 51.2 51.2 134.4 0 185.6v0c-25.6 22.4-57.6 35.2-92.8 35.2zM259.2 678.4c-19.2 0-35.2 6.4-48 19.2s-19.2 28.8-19.2 48 6.4 35.2 19.2 48c25.6 25.6 67.2 25.6 92.8 0s25.6-67.2 0-92.8c-9.6-16-25.6-22.4-44.8-22.4z"],"attrs":[{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["webhooks"],"grid":14},"attrs":[{},{},{},{},{},{},{},{}],"properties":{"order":92,"id":29,"name":"rules","prevSize":28,"code":59719},"setIdx":4,"setId":1,"iconIdx":118}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showCodes":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon"},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"name":"icomoon","classSelector":".icon"},"historySize":50}} \ No newline at end of file +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M128 170.667v298.667c0 58.88 23.936 112.299 62.464 150.869s91.989 62.464 150.869 62.464h409.003l-140.501 140.501c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0l213.333-213.333c3.925-3.925 7.083-8.619 9.259-13.824s3.243-10.795 3.243-16.341c0-10.923-4.181-21.845-12.501-30.165l-213.333-213.333c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331l140.501 140.501h-409.003c-35.371 0-67.285-14.293-90.496-37.504s-37.504-55.125-37.504-90.496v-298.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["corner-down-right"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59767,"name":"corner-down-right"},"setIdx":0,"setId":3,"iconIdx":0},{"icon":{"paths":["M470 384v-86h84v86h-84zM512 854c188 0 342-154 342-342s-154-342-342-342-342 154-342 342 154 342 342 342zM512 86c236 0 426 190 426 426s-190 426-426 426-426-190-426-426 190-426 426-426zM470 726v-256h84v256h-84z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["info_outline"],"grid":24},"attrs":[{}],"properties":{"order":128,"id":0,"prevSize":24,"code":59764,"name":"info-outline"},"setIdx":2,"setId":1,"iconIdx":45},{"icon":{"paths":["M214 768h596v86h-596v-86zM384 682v-256h-170l298-298 298 298h-170v256h-256z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["file_upload"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59762,"name":"upload-2"},"setIdx":2,"setId":1,"iconIdx":46},{"icon":{"paths":["M678 726h138l-70-186zM790 426l192 512h-86l-48-128h-202l-48 128h-86l192-512h86zM550 642l-34 88-132-132-214 212-60-60 218-214c-54-60-96-124-128-194h86c26 50 58 98 98 142 62-68 108-146 136-228h-478v-86h300v-84h84v84h300v86h-126c-32 100-84 196-158 278l-2 2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["translate"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59759,"name":"translate"},"setIdx":2,"setId":1,"iconIdx":47},{"icon":{"paths":["M854 470v84h-520l238 240-60 60-342-342 342-342 60 60-238 240h520z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow_back"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":24,"code":59758,"name":"arrow_back"},"setIdx":2,"setId":1,"iconIdx":48},{"icon":{"paths":["M768 512c-25.6 0-42.667 17.067-42.667 42.667v256c0 25.6-17.067 42.667-42.667 42.667h-469.333c-25.6 0-42.667-17.067-42.667-42.667v-469.333c0-25.6 17.067-42.667 42.667-42.667h256c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667h-256c-72.533 0-128 55.467-128 128v469.333c0 72.533 55.467 128 128 128h469.333c72.533 0 128-55.467 128-128v-256c0-25.6-17.067-42.667-42.667-42.667z","M934.4 110.933c-4.267-8.533-12.8-17.067-21.333-21.333-4.267-4.267-12.8-4.267-17.067-4.267h-256c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h153.6l-396.8 396.8c-17.067 17.067-17.067 42.667 0 59.733 8.533 8.533 17.067 12.8 29.867 12.8s21.333-4.267 29.867-12.8l396.8-396.8v153.6c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-256c0-4.267 0-12.8-4.267-17.067z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["external-link"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":2,"prevSize":24,"code":59757,"name":"external-link"},"setIdx":2,"setId":1,"iconIdx":49},{"icon":{"paths":["M810.667 85.333h-597.333c-72.533 0-128 55.467-128 128v597.333c0 72.533 55.467 128 128 128h597.333c72.533 0 128-55.467 128-128v-597.333c0-72.533-55.467-128-128-128zM853.333 810.667c0 25.6-17.067 42.667-42.667 42.667h-597.333c-25.6 0-42.667-17.067-42.667-42.667v-597.333c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v597.333z","M682.667 469.333h-341.333c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h341.333c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["minus-square"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":3,"prevSize":24,"code":59753,"name":"minus-square"},"setIdx":2,"setId":1,"iconIdx":50},{"icon":{"paths":["M810.667 85.333h-597.333c-72.533 0-128 55.467-128 128v597.333c0 72.533 55.467 128 128 128h597.333c72.533 0 128-55.467 128-128v-597.333c0-72.533-55.467-128-128-128zM853.333 810.667c0 25.6-17.067 42.667-42.667 42.667h-597.333c-25.6 0-42.667-17.067-42.667-42.667v-597.333c0-25.6 17.067-42.667 42.667-42.667h597.333c25.6 0 42.667 17.067 42.667 42.667v597.333z","M682.667 469.333h-128v-128c0-25.6-17.067-42.667-42.667-42.667s-42.667 17.067-42.667 42.667v128h-128c-25.6 0-42.667 17.067-42.667 42.667s17.067 42.667 42.667 42.667h128v128c0 25.6 17.067 42.667 42.667 42.667s42.667-17.067 42.667-42.667v-128h128c25.6 0 42.667-17.067 42.667-42.667s-17.067-42.667-42.667-42.667z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["plus-square"],"grid":24},"attrs":[{},{}],"properties":{"order":1,"id":4,"name":"plus-square","prevSize":24,"code":59752},"setIdx":2,"setId":1,"iconIdx":51},{"icon":{"paths":["M170 640v-86h684v86h-684zM854 384v86h-684v-86h684z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["drag_handle"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":5,"prevSize":24,"code":59745,"name":"drag2"},"setIdx":2,"setId":1,"iconIdx":52},{"icon":{"paths":["M854 682v-512h-684v598l86-86h598zM854 86c46 0 84 38 84 84v512c0 46-38 86-84 86h-598l-170 170v-768c0-46 38-84 84-84h684z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["chat_bubble_outline"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":6,"name":"comments","prevSize":24,"code":59743},"setIdx":2,"setId":1,"iconIdx":53},{"icon":{"paths":["M512 128c212 0 384 172 384 384s-172 384-384 384c-88 0-170-30-234-80l60-60c50 34 110 54 174 54 166 0 298-132 298-298s-132-298-298-298-298 132-298 298h128l-172 170-170-170h128c0-212 172-384 384-384zM598 512c0 46-40 86-86 86s-86-40-86-86 40-86 86-86 86 40 86 86z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["settings_backup_restore"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":7,"prevSize":24,"code":59739,"name":"backup"},"setIdx":2,"setId":1,"iconIdx":54},{"icon":{"paths":["M726 512c0 24-20 42-44 42h-426l-170 172v-598c0-24 18-42 42-42h554c24 0 44 18 44 42v384zM896 256c24 0 42 18 42 42v640l-170-170h-470c-24 0-42-18-42-42v-86h554v-384h86z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["question_answer"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":8,"prevSize":24,"code":59738,"name":"support"},"setIdx":2,"setId":1,"iconIdx":55},{"icon":{"paths":["M918 384v128h-128v298h-128v-298h-128v-128h384zM106 170h556v128h-214v512h-128v-512h-214v-128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["text_fields"],"grid":24},"attrs":[{}],"properties":{"order":75,"id":9,"prevSize":24,"code":59705,"name":"control-RichText"},"setIdx":2,"setId":1,"iconIdx":56},{"icon":{"paths":["M640 85.333q78 0 149.167 30.5t122.5 81.833 81.833 122.5 30.5 149.167q0 85-35 160.667t-96.667 129.167-140 77.5l21-20.667q18-18.333 28-42.667 9.333-22.667 9.333-49.333 0-6.667-0.333-9.333 59.333-41.333 93.833-105.833t34.5-139.5q0-60.667-23.667-116t-63.667-95.333-95.333-63.667-116-23.667q-55.333 0-106.5 19.833t-90 53.833-65 81.333-33.833 101h-88.667q-70.667 0-120.667 50t-50 120.667q0 38.667 15.167 71.667t39.833 54.167 54.833 33 60.833 11.833h50q11.667 29.333 30 48l37.667 37.333h-117.667q-69.667 0-128.5-34.333t-93.167-93.167-34.333-128.5 34.333-128.5 93.167-93.167 128.5-34.333h22q26.333-74.333 79.333-132.167t126.833-90.833 155.833-33zM554.667 426.667q17.667 0 30.167 12.5t12.5 30.167v281l55-55.333q12.333-12.333 30.333-12.333 18.333 0 30.5 12.167t12.167 30.5q0 18-12.333 30.333l-128 128q-12.333 12.333-30.333 12.333t-30.333-12.333l-128-128q-12.333-13-12.333-30.333 0-17.667 12.5-30.167t30.167-12.5q18 0 30.333 12.333l55 55.333v-281q0-17.667 12.5-30.167t30.167-12.5z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["cloud-download"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":10,"prevSize":24,"code":59710,"name":"download"},"setIdx":2,"setId":1,"iconIdx":57},{"icon":{"paths":["M512 682.667h-341.333c-5.845 0-11.349-1.152-16.299-3.2-5.205-2.133-9.899-5.333-13.867-9.301s-7.125-8.661-9.301-13.867c-2.048-4.949-3.2-10.453-3.2-16.299v-426.667c0-5.845 1.152-11.349 3.2-16.299 2.133-5.205 5.333-9.899 9.301-13.867s8.661-7.125 13.867-9.301c4.949-2.048 10.453-3.2 16.299-3.2h682.667c5.845 0 11.349 1.152 16.299 3.2 5.205 2.133 9.899 5.333 13.867 9.301s7.125 8.661 9.301 13.867c2.048 4.949 3.2 10.453 3.2 16.299v426.667c0 5.845-1.152 11.349-3.2 16.299-2.133 5.205-5.333 9.899-9.301 13.867s-8.661 7.125-13.867 9.301c-4.949 2.048-10.453 3.2-16.299 3.2zM469.333 768v85.333h-128c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-128v-85.333h298.667c17.28 0 33.835-3.456 48.981-9.728 15.701-6.485 29.781-16 41.557-27.776s21.291-25.856 27.776-41.557c6.229-15.104 9.685-31.659 9.685-48.939v-426.667c0-17.28-3.456-33.835-9.728-48.981-6.485-15.701-16-29.781-27.776-41.557s-25.856-21.291-41.557-27.776c-15.104-6.229-31.659-9.685-48.939-9.685h-682.667c-17.28 0-33.835 3.456-48.981 9.728-15.659 6.485-29.739 16-41.515 27.776s-21.291 25.856-27.776 41.515c-6.272 15.147-9.728 31.701-9.728 48.981v426.667c0 17.28 3.456 33.835 9.728 48.981 6.485 15.701 16 29.781 27.776 41.557s25.856 21.291 41.557 27.776c15.104 6.229 31.659 9.685 48.939 9.685z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["monitor"],"grid":0},"attrs":[{}],"properties":{"order":132,"id":0,"prevSize":24,"code":59765,"name":"type-UI"},"setIdx":2,"setId":1,"iconIdx":0},{"icon":{"paths":["M66.337 575.491l276.668-171.531v-57.177l-331.627 207.614v42.189l331.627 207.614-0-57.177z","M957.663 575.49l-276.668-171.531v-57.177l331.627 207.614v42.189l-331.627 207.614 0-57.177z","M583.295 214.183l-200.825 621.623 53.007 17.527 200.837-621.623z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["prerender"],"grid":0},"attrs":[{},{},{}],"properties":{"order":114,"id":0,"name":"prerender","prevSize":24,"code":59724},"setIdx":2,"setId":1,"iconIdx":1},{"icon":{"paths":["M1024 512c0 282.77-229.23 512-512 512s-512-229.23-512-512c0-282.77 229.23-512 512-512s512 229.23 512 512z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["circle"],"grid":0},"attrs":[{}],"properties":{"order":106,"id":1,"name":"circle","prevSize":24,"code":59729},"setIdx":2,"setId":1,"iconIdx":2},{"icon":{"paths":["M512 0c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h128v870.4h-128c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h307.2c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6h-128v-870.4h128c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6h-307.2zM51.2 204.8c-28.16 0-51.2 23.040-51.2 51.2v460.8c0 28.16 23.040 51.2 51.2 51.2h537.6v-51.2h-512c-15.36 0-25.6-10.24-25.6-25.6v-409.6c0-15.36 10.24-25.6 25.6-25.6h512v-51.2h-537.6zM742.4 204.8v51.2h204.8c15.36 0 25.6 10.24 25.6 25.6v409.6c0 15.36-10.24 25.6-25.6 25.6h-204.8v51.2h230.4c28.16 0 51.2-23.040 51.2-51.2v-460.8c0-28.16-23.040-51.2-51.2-51.2h-230.4z","M386.56 606.72c0 12.8-7.68 23.040-20.48 25.6-28.16 10.24-58.88 15.36-92.16 15.36-35.84 0-66.56-10.24-84.48-25.6s-25.6-38.4-25.6-66.56 10.24-51.2 25.6-66.56c17.92-17.92 46.080-23.040 84.48-23.040h69.12v-38.4c0-35.84-25.6-53.76-64-53.76-23.040 0-46.080 7.68-69.12 20.48-2.56 2.56-5.12 2.56-10.24 2.56-10.24 0-20.48-7.68-20.48-20.48 0-7.68 2.56-12.8 10.24-17.92 30.72-20.48 61.44-25.6 92.16-25.6 56.32 0 104.96 30.72 104.96 92.16v181.76zM345.6 501.76h-69.12c-61.44 0-69.12 28.16-69.12 53.76s7.68 56.32 69.12 56.32c23.040 0 46.080-2.56 69.12-10.24v-99.84z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Slug"],"grid":0},"attrs":[{},{}],"properties":{"order":103,"id":2,"name":"control-Slug","prevSize":24,"code":59727},"setIdx":2,"setId":1,"iconIdx":3},{"icon":{"paths":["M295.954 822.751h-94.705c-47.353 0-88.786-41.434-88.786-88.786v-491.283c0-47.353 41.434-88.786 88.786-88.786h94.705v-59.191h-94.705c-82.867 0-147.977 65.11-147.977 147.977v491.283c0 82.867 65.11 147.977 147.977 147.977h94.705v-59.191z","M970.728 473.526c-82.867-171.653-201.249-378.821-272.277-378.821h-112.462v59.191h112.462c35.514 11.838 136.139 177.572 213.087 337.387-76.948 153.896-177.572 325.549-213.087 337.387h-112.462v59.191h112.462c71.029 0 183.491-207.168 272.277-384.74l5.919-11.838-5.919-17.757z","M266.358 337.341v260.462h59.191v-260.462z","M479.422 337.341v260.462h59.191v-260.462z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["Tags"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":98,"id":3,"name":"type-Tags","prevSize":24,"code":59722},"setIdx":2,"setId":1,"iconIdx":4},{"icon":{"paths":["M512 102.4c-200.4 0-366.954 144.072-402.4 334.2-0.031 0.165-0.069 0.335-0.1 0.5-2.974 16.061-4.76 32.441-5.8 49.1-0.017 0.271-0.084 0.529-0.1 0.8 0.019 0.004 0.080-0.004 0.1 0-0.503 8.31-1.3 16.564-1.3 25 0 226.202 183.398 409.6 409.6 409.6 208.165 0 379.707-155.44 405.8-356.5 0.004-0.033-0.004-0.067 0-0.1 1.94-14.978 3.124-30.16 3.4-45.6 0.044-2.487 0.4-4.903 0.4-7.4 0-226.202-183.398-409.6-409.6-409.6zM512 153.6c185.461 0 337.902 140.924 356.4 321.5-35.181-21.812-84.232-39.9-151.6-39.9-85.35 0-140.891 41.606-194.6 81.9-49.152 36.864-95.55 71.7-163.8 71.7-86.067 0-135.862-54.67-175.9-98.6-9.001-9.901-17.11-17.483-25.4-25.3 23.131-175.603 172.981-311.3 354.9-311.3zM716.8 486.4c77.828 0 125.173 28.221 152.2 52.8-13.96 185.173-168.254 331.2-357 331.2-190.097 0-345.175-148.14-357.2-335.2 41.826 45.372 102.577 104.8 203.6 104.8 85.35 0 140.891-41.606 194.6-81.9 49.152-36.915 95.55-71.7 163.8-71.7z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["activity"],"grid":0},"attrs":[{}],"properties":{"order":12,"id":4,"name":"activity, history, time","prevSize":24,"code":59652},"setIdx":2,"setId":1,"iconIdx":5},{"icon":{"paths":["M512 0c-35.392 0-64 28.608-64 64v384h-384c-35.392 0-64 28.608-64 64s28.608 64 64 64h384v384c0 35.392 28.608 64 64 64s64-28.608 64-64v-384h384c35.392 0 64-28.608 64-64s-28.608-64-64-64h-384v-384c0-35.392-28.608-64-64-64z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["add"],"grid":0},"attrs":[{}],"properties":{"order":13,"id":5,"name":"add, plus","prevSize":24,"code":59653},"setIdx":2,"setId":1,"iconIdx":6},{"icon":{"paths":["M512 102.4c-226.202 0-409.6 183.398-409.6 409.6s183.398 409.6 409.6 409.6c226.202 0 409.6-183.398 409.6-409.6s-183.398-409.6-409.6-409.6zM512 153.6c197.632 0 358.4 160.819 358.4 358.4s-160.768 358.4-358.4 358.4c-197.632 0-358.4-160.819-358.4-358.4s160.768-358.4 358.4-358.4zM691.9 333c-12.893 0.002-25.782 4.882-35.5 14.6l-222.2 221.9-67.7-67.5c-19.19-19.294-51.085-19.215-70.3 0-19.15 19.15-19.15 51.050 0 70.2 0.198 0.2 26.198 26.681 52 53 12.95 13.209 25.761 26.372 35.2 36 4.719 4.814 8.607 8.755 11.2 11.4 1.296 1.322 2.293 2.281 2.9 2.9 0.279 0.282 0.488 0.486 0.6 0.6 0.001 0.001 7.591-7.429 14.6-14.3l-14.5 14.4 0.2 0.2v0.1c19.43 19.327 51.57 19.327 71 0v-0.1l258.1-257.6c19.546-19.447 19.521-51.885-0.1-71.3-9.731-9.679-22.607-14.502-35.5-14.5z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["check-circle"],"grid":0},"attrs":[{}],"properties":{"order":14,"id":6,"name":"check-circle","prevSize":24,"code":59654},"setIdx":2,"setId":1,"iconIdx":7},{"icon":{"paths":["M512 1024c-282.778 0-512-229.222-512-512s229.222-512 512-512 512 229.222 512 512-229.222 512-512 512zM855.808 270.592c-19.2-19.2-50.278-19.2-69.478 0l-376.73 376.73-171.878-171.93c-19.2-19.2-50.278-19.2-69.478 0s-19.2 50.278 0 69.478c0 0 201.523 205.261 204.8 208.486 9.984 10.138 23.347 14.643 36.557 14.080 13.21 0.563 26.573-3.942 36.608-14.029 3.277-3.226 409.6-413.286 409.6-413.286 19.2-19.2 19.2-50.33 0-69.53z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["check-circle-filled"],"grid":0},"attrs":[{}],"properties":{"order":27,"id":7,"name":"check-circle-filled","prevSize":24,"code":59655},"setIdx":2,"setId":1,"iconIdx":8},{"icon":{"paths":["M601.024 512l276.736 276.736c24.512 24.576 24.512 64.384 0 89.024-24.64 24.576-64.384 24.576-89.024 0l-276.736-276.736-276.736 276.736c-24.512 24.576-64.384 24.576-89.024 0-24.512-24.64-24.512-64.448 0-89.024l276.736-276.736-276.736-276.736c-24.512-24.576-24.512-64.384 0-89.024 24.64-24.576 64.512-24.576 89.024 0l276.736 276.736 276.736-276.736c24.64-24.576 64.384-24.576 89.024 0 24.512 24.64 24.512 64.448 0 89.024l-276.736 276.736z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["close"],"grid":0},"attrs":[{}],"properties":{"order":28,"id":8,"name":"close","prevSize":24,"code":59656},"setIdx":2,"setId":1,"iconIdx":9},{"icon":{"paths":["M409.6 435.2h-153.6v51.2h153.6v-51.2zM409.6 332.8h-153.6v51.2h153.6v-51.2zM256 691.2h409.6v-51.2h-409.6v51.2zM409.6 230.4h-153.6v51.2h153.6v-51.2zM870.4 179.2h-51.2v-51.2c0-28.262-22.938-51.2-51.2-51.2h-614.4c-28.262 0-51.2 22.938-51.2 51.2v665.6c0 28.262 22.938 51.2 51.2 51.2h51.2v51.2c0 28.262 22.938 51.2 51.2 51.2h614.4c28.262 0 51.2-22.938 51.2-51.2v-665.6c0-28.262-22.938-51.2-51.2-51.2zM179.2 793.6c-14.157 0-25.6-11.443-25.6-25.6v-614.4c0-14.131 11.443-25.6 25.6-25.6h563.2c14.157 0 25.6 11.469 25.6 25.6v614.4c0 14.157-11.443 25.6-25.6 25.6h-563.2zM870.4 870.4c0 14.157-11.443 25.6-25.6 25.6h-563.2c-14.157 0-25.6-11.443-25.6-25.6v-25.6h512c28.262 0 51.2-22.938 51.2-51.2v-563.2h25.6c14.157 0 25.6 11.469 25.6 25.6v614.4zM614.4 230.4h-102.4c-28.262 0-51.2 22.938-51.2 51.2v153.6c0 28.262 22.938 51.2 51.2 51.2h102.4c28.262 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.938-51.2-51.2-51.2zM614.4 435.2h-102.4v-153.6h102.4v153.6zM256 588.8h409.6v-51.2h-409.6v51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["content"],"grid":0},"attrs":[{}],"properties":{"order":37,"id":9,"name":"type-References","prevSize":24,"code":59657},"setIdx":2,"setId":1,"iconIdx":10},{"icon":{"paths":["M793.6 844.8c0 14.157-11.443 25.6-25.6 25.6h-665.6c-14.131 0-25.6-11.443-25.6-25.6v-665.6c0-14.157 11.469-25.6 25.6-25.6h665.6c14.157 0 25.6 11.443 25.6 25.6v102.4h51.2v-128c0-28.262-22.938-51.2-51.2-51.2h-716.8c-28.262 0-51.2 22.938-51.2 51.2v716.8c0 28.262 22.938 51.2 51.2 51.2h716.8c28.262 0 51.2-22.938 51.2-51.2v-281.6h-51.2v256zM991.078 237.747c-9.958-9.958-26.035-9.958-35.968 0l-391.91 391.91-238.31-238.31c-9.958-9.958-26.061-9.958-35.942 0-9.958 9.907-9.958 26.010 0 35.942l254.874 254.874c0.461 0.538 0.614 1.203 1.126 1.69 5.043 5.018 11.674 7.475 18.278 7.373 6.605 0.102 13.235-2.355 18.278-7.373 0.512-0.512 0.666-1.178 1.126-1.69l408.448-408.474c9.933-9.933 9.933-26.035 0-35.942z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-checkbox"],"grid":0},"attrs":[{}],"properties":{"order":38,"id":10,"name":"control-Checkbox","prevSize":24,"code":59658},"setIdx":2,"setId":1,"iconIdx":11},{"icon":{"paths":["M51.2 0c-28.262 0-51.2 22.938-51.2 51.2v281.6c0 28.262 22.938 51.2 51.2 51.2h921.6c28.262 0 51.2-22.938 51.2-51.2v-281.6c0-28.262-22.938-51.2-51.2-51.2h-921.6zM76.8 51.2h512v281.6h-512c-14.157 0-25.6-11.443-25.6-25.6v-230.4c0-14.157 11.443-25.6 25.6-25.6zM640 51.2h307.2c14.157 0 25.6 11.443 25.6 25.6v230.4c0 14.157-11.443 25.6-25.6 25.6h-307.2v-281.6zM716.8 153.6c-0.41 0.358 89.139 102.938 89.6 102.4 0.512 0 89.6-95.36 89.6-102.4 0 0.384-172.16 0-179.2 0zM128 435.2c-42.394 0-76.8 34.406-76.8 76.8s34.406 76.8 76.8 76.8c42.394 0 76.8-34.406 76.8-76.8s-34.406-76.8-76.8-76.8zM128 486.4c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6c-14.157 0-25.6-11.443-25.6-25.6s11.443-25.6 25.6-25.6zM307.2 486.4c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h640c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-640zM128 640c-42.394 0-76.8 34.381-76.8 76.8s34.406 76.8 76.8 76.8c42.394 0 76.8-34.381 76.8-76.8s-34.406-76.8-76.8-76.8zM128 691.2c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6c-14.157 0-25.6-11.443-25.6-25.6s11.443-25.6 25.6-25.6zM307.2 691.2c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h640c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-640zM128 844.8c-42.394 0-76.8 34.381-76.8 76.8s34.406 76.8 76.8 76.8c42.394 0 76.8-34.381 76.8-76.8s-34.406-76.8-76.8-76.8zM128 896c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6c-14.157 0-25.6-11.443-25.6-25.6s11.443-25.6 25.6-25.6zM307.2 896c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h640c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-640z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-dropdown"],"grid":0},"attrs":[{}],"properties":{"order":39,"id":11,"name":"control-Dropdown","prevSize":24,"code":59659},"setIdx":2,"setId":1,"iconIdx":12},{"icon":{"paths":["M512 0c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h128v870.4h-128c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h307.2c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-128v-870.4h128c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-307.2zM51.2 204.8c-28.262 0-51.2 22.938-51.2 51.2v460.8c0 28.262 22.938 51.2 51.2 51.2h537.6v-51.2h-512c-14.131 0-25.6-11.443-25.6-25.6v-409.6c0-14.157 11.469-25.6 25.6-25.6h512v-51.2h-537.6zM742.4 204.8v51.2h204.8c14.157 0 25.6 11.443 25.6 25.6v409.6c0 14.157-11.443 25.6-25.6 25.6h-204.8v51.2h230.4c28.262 0 51.2-22.938 51.2-51.2v-460.8c0-28.262-22.938-51.2-51.2-51.2h-230.4zM285.9 307c-0.589 0.051-1.161 0.048-1.75 0.15-8.243 0.051-16.396 4.474-20.85 13.050l-132.55 306.25c-6.656 12.749-2.866 28.981 8.5 36.2 11.341 7.219 25.97 2.749 32.6-10l27.65-63.85h170.5c0.512 0 0.914-0.224 1.4-0.25l27.45 64.050c6.63 12.749 21.136 17.269 32.4 10.050s15.005-23.451 8.4-36.2l-131.3-306.25c-4.454-8.576-12.432-12.973-20.65-13.050-0.614-0.102-1.211-0.099-1.8-0.15zM285.9 389.15l63.65 148.45h-127.9l64.25-148.45z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-input"],"grid":0},"attrs":[{}],"properties":{"order":41,"id":12,"name":"control-Input","prevSize":24,"code":59660},"setIdx":2,"setId":1,"iconIdx":13},{"icon":{"paths":["M153.6 716.8c-84.787 0-153.6 68.813-153.6 153.6s68.813 153.6 153.6 153.6c84.787 0 153.6-68.813 153.6-153.6s-68.813-153.6-153.6-153.6zM153.6 972.8c-56.55 0-102.4-45.85-102.4-102.4s45.85-102.4 102.4-102.4c56.55 0 102.4 45.85 102.4 102.4s-45.85 102.4-102.4 102.4zM384 179.2h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6zM998.4 486.4h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6zM153.6 0c-84.787 0-153.6 68.787-153.6 153.6s68.813 153.6 153.6 153.6c84.787 0 153.6-68.787 153.6-153.6s-68.813-153.6-153.6-153.6zM153.6 256c-56.55 0-102.4-45.85-102.4-102.4s45.85-102.4 102.4-102.4c56.55 0 102.4 45.85 102.4 102.4s-45.85 102.4-102.4 102.4zM153.6 358.4c-84.787 0-153.6 68.787-153.6 153.6 0 84.787 68.813 153.6 153.6 153.6s153.6-68.813 153.6-153.6c0-84.813-68.813-153.6-153.6-153.6zM153.6 614.4c-56.55 0-102.4-45.85-102.4-102.4s45.85-102.4 102.4-102.4c56.55 0 102.4 45.85 102.4 102.4s-45.85 102.4-102.4 102.4zM153.6 102.4c-28.262 0-51.2 22.938-51.2 51.2s22.938 51.2 51.2 51.2c28.262 0 51.2-22.938 51.2-51.2s-22.938-51.2-51.2-51.2zM998.4 844.8h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-radio"],"grid":0},"attrs":[{}],"properties":{"order":42,"id":13,"name":"control-Radio","prevSize":24,"code":59661},"setIdx":2,"setId":1,"iconIdx":14},{"icon":{"paths":["M0 0v204.8h76.8v76.8h51.2v-76.8h76.8v-204.8h-204.8zM819.2 0v204.8h204.8v-204.8h-204.8zM51.2 51.2h102.4v102.4h-102.4v-102.4zM870.4 51.2h102.4v102.4h-102.4v-102.4zM281.6 76.8v51.2h102.4v-51.2h-102.4zM486.4 76.8v51.2h102.4v-51.2h-102.4zM691.2 76.8v51.2h102.4v-51.2h-102.4zM333.25 204.8c-7.091-0.307-14.348 2.097-19.75 7.55l-74.75 74.75c-10.317 10.291-10.317 27.083 0 37.4s27.059 10.317 37.35 0l68.45-68.5h141.85v486.4h-50.7c-7.117-0.307-14.348 2.097-19.75 7.55l-23.6 23.55c-10.317 10.317-10.317 27.083 0 37.4 10.291 10.317 27.109 10.317 37.4 0l17.25-17.3h129.75l18.050 18c10.394 10.368 27.181 10.368 37.6 0 10.368-10.394 10.368-27.181 0-37.6l-24-24c-5.478-5.478-12.682-7.907-19.85-7.6h-50.95v-486.4h141.55l69.25 69.2c10.394 10.368 27.155 10.368 37.6 0 10.368-10.368 10.368-27.181 0-37.6l-75.2-75.2c-5.478-5.478-12.706-7.907-19.9-7.6h-357.65zM896 281.6v102.4h51.2v-102.4h-51.2zM76.8 384v102.4h51.2v-102.4h-51.2zM896 486.4v102.4h51.2v-102.4h-51.2zM76.8 588.8v102.4h51.2v-102.4h-51.2zM896 691.2v102.4h51.2v-102.4h-51.2zM76.8 793.6v25.6h-76.8v204.8h204.8v-76.8h76.8v-51.2h-76.8v-76.8h-76.8v-25.6h-51.2zM819.2 819.2v76.8h-25.6v51.2h25.6v76.8h204.8v-204.8h-204.8zM51.2 870.4h102.4v102.4h-102.4v-102.4zM870.4 870.4h102.4v102.4h-102.4v-102.4zM384 896v51.2h102.4v-51.2h-102.4zM588.8 896v51.2h102.4v-51.2h-102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-textarea"],"grid":0},"attrs":[{}],"properties":{"order":17,"id":14,"name":"control-TextArea","prevSize":24,"code":59662},"setIdx":2,"setId":1,"iconIdx":15},{"icon":{"paths":["M332.8 25.6c-127.258 0-230.4 103.142-230.4 230.4s103.142 230.4 230.4 230.4h358.4c127.258 0 230.4-103.142 230.4-230.4s-103.142-230.4-230.4-230.4h-358.4zM332.8 76.8h358.4c98.97 0 179.2 80.23 179.2 179.2s-80.23 179.2-179.2 179.2h-358.4c-98.97 0-179.2-80.23-179.2-179.2s80.23-179.2 179.2-179.2zM332.8 128c-70.707 0-128 57.293-128 128s57.293 128 128 128c70.707 0 128-57.293 128-128s-57.293-128-128-128zM332.8 179.2c42.419 0 76.8 34.381 76.8 76.8s-34.381 76.8-76.8 76.8c-42.419 0-76.8-34.381-76.8-76.8s34.381-76.8 76.8-76.8zM332.8 537.6c-127.258 0-230.4 103.142-230.4 230.4s103.142 230.4 230.4 230.4h358.4c127.258 0 230.4-103.142 230.4-230.4s-103.142-230.4-230.4-230.4h-358.4zM332.8 588.8h358.4c98.97 0 179.2 80.23 179.2 179.2s-80.23 179.2-179.2 179.2h-358.4c-98.97 0-179.2-80.23-179.2-179.2s80.23-179.2 179.2-179.2zM691.2 640c-70.707 0-128 57.293-128 128s57.293 128 128 128c70.707 0 128-57.293 128-128s-57.293-128-128-128zM691.2 691.2c42.419 0 76.8 34.381 76.8 76.8s-34.381 76.8-76.8 76.8c-42.419 0-76.8-34.381-76.8-76.8s34.381-76.8 76.8-76.8z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-toggle"],"grid":0},"attrs":[{}],"properties":{"order":16,"id":15,"name":"control-Toggle","prevSize":24,"code":59663},"setIdx":2,"setId":1,"iconIdx":16},{"icon":{"paths":["M204.8 51.2c-56.525 0-102.4 45.875-102.4 102.4v512c0 56.525 45.875 102.4 102.4 102.4h409.6c56.525 0 102.4-45.875 102.4-102.4v-512c0-56.525-45.875-102.4-102.4-102.4h-409.6zM204.8 102.4h409.6c28.262 0 51.2 22.886 51.2 51.2v512c0 28.314-22.938 51.2-51.2 51.2h-409.6c-28.262 0-51.2-22.886-51.2-51.2v-512c0-28.314 22.938-51.2 51.2-51.2zM768 204.8v51.2c28.262 0 51.2 22.886 51.2 51.2v512c0 28.314-22.938 51.2-51.2 51.2h-409.6c-28.262 0-51.2-22.886-51.2-51.2h-51.2c0 56.525 45.875 102.4 102.4 102.4h409.6c56.525 0 102.4-45.875 102.4-102.4v-512c0-56.525-45.875-102.4-102.4-102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["copy"],"grid":0},"attrs":[{}],"properties":{"order":90,"id":16,"name":"copy","prevSize":24,"code":59664},"setIdx":2,"setId":1,"iconIdx":17},{"icon":{"paths":["M828.8 1024h-633.6c-105.6 0-195.2-89.6-195.2-195.2v-320c0-281.6 227.2-508.8 505.6-508.8 288 0 518.4 230.4 518.4 518.4v310.4c0 105.6-89.6 195.2-195.2 195.2zM505.6 64c-243.2 0-441.6 198.4-441.6 441.6v320c0 73.6 60.8 134.4 131.2 134.4h630.4c73.6 0 131.2-60.8 131.2-131.2v-310.4c3.2-249.6-201.6-454.4-451.2-454.4z","M512 668.8c-3.2 0-6.4 0-6.4 0-32-3.2-64-19.2-80-48l-192-278.4c-9.6-9.6-9.6-25.6-0-38.4 9.6-9.6 25.6-12.8 38.4-6.4l294.4 172.8c28.8 16 48 44.8 51.2 76.8s-6.4 64-28.8 89.6c-19.2 22.4-48 32-76.8 32zM364.8 428.8l108.8 160c6.4 9.6 19.2 19.2 32 19.2s25.6-3.2 35.2-12.8c9.6-9.6 12.8-22.4 9.6-35.2s-9.6-22.4-19.2-32l-166.4-99.2z","M678.4 364.8c-6.4 0-12.8-3.2-19.2-6.4-16-9.6-19.2-28.8-9.6-44.8l54.4-83.2c9.6-16 28.8-19.2 44.8-9.6 19.2 12.8 22.4 35.2 12.8 48l-54.4 83.2c-6.4 9.6-16 12.8-28.8 12.8z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["dashboard"],"grid":0},"attrs":[{},{},{}],"properties":{"order":26,"id":17,"name":"dashboard","prevSize":24,"code":59665},"setIdx":2,"setId":1,"iconIdx":18},{"icon":{"paths":["M597.35 819.2c14.131 0 25.6-11.469 25.6-25.6v-307.2c0-14.080-11.469-25.6-25.6-25.6s-25.6 11.52-25.6 25.6v307.2c0 14.131 11.418 25.6 25.6 25.6zM776.55 204.8h-153.6v-51.2c0-28.314-22.886-51.2-51.2-51.2h-102.4c-28.262 0-51.2 22.886-51.2 51.2v51.2h-153.6c-28.262 0-51.2 22.886-51.2 51.2v102.4c0 28.314 22.938 51.2 51.2 51.2v460.8c0 28.314 22.938 51.2 51.2 51.2h409.6c28.314 0 51.2-22.886 51.2-51.2v-460.8c28.314 0 51.2-22.886 51.2-51.2v-102.4c0-28.314-22.938-51.2-51.2-51.2zM469.35 153.6h102.4v51.2h-102.4v-51.2zM725.35 870.4h-409.6v-460.8h409.6v460.8zM776.55 358.4h-512v-102.4h512v102.4zM443.75 819.2c14.131 0 25.6-11.469 25.6-25.6v-307.2c0-14.080-11.469-25.6-25.6-25.6s-25.6 11.52-25.6 25.6v307.2c0 14.131 11.469 25.6 25.6 25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["delete"],"grid":0},"attrs":[{}],"properties":{"order":29,"id":18,"name":"delete, bin","prevSize":24,"code":59666},"setIdx":2,"setId":1,"iconIdx":19},{"icon":{"paths":["M832 128h-192v-64c0-35.392-28.608-64-64-64h-128c-35.328 0-64 28.608-64 64v64h-192c-35.328 0-64 28.608-64 64v128c0 35.392 28.672 64 64 64v512c0 35.392 28.672 64 64 64h512c35.392 0 64-28.608 64-64v-512c35.392 0 64-28.608 64-64v-128c0-35.392-28.608-64-64-64zM448 64h128v64h-128v-64zM448 800c0 17.664-14.336 32-32 32s-32-14.336-32-32v-320c0-17.6 14.336-32 32-32s32 14.4 32 32v320zM640 800c0 17.664-14.336 32-32 32s-32-14.336-32-32v-320c0-17.6 14.336-32 32-32s32 14.4 32 32v320zM832 320h-640v-128h640v128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["delete-filled"],"grid":0},"attrs":[{}],"properties":{"order":36,"id":19,"name":"delete-filled","prevSize":24,"code":59667},"setIdx":2,"setId":1,"iconIdx":20},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-343.4zM716.8 189.8l117.4 117.4h-117.4v-117.4zM332.8 460.8c-127.232 0-230.4 103.168-230.4 230.4s103.168 230.4 230.4 230.4c127.232 0 230.4-103.168 230.4-230.4s-103.168-230.4-230.4-230.4zM332.8 512c98.816 0 179.2 80.384 179.2 179.2s-80.384 179.2-179.2 179.2c-98.816 0-179.2-80.384-179.2-179.2s80.384-179.2 179.2-179.2zM227.2 665.6c-12.39 0-22.4 10.061-22.4 22.4v6.4c0 12.39 10.010 22.4 22.4 22.4h211.2c12.39 0 22.4-10.010 22.4-22.4v-6.4c0-12.39-10.061-22.4-22.4-22.4h-211.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-delete"],"grid":0},"attrs":[{}],"properties":{"order":35,"id":20,"name":"document-delete","prevSize":24,"code":59668},"setIdx":2,"setId":1,"iconIdx":21},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-343.4zM716.8 189.8l117.4 117.4h-117.4v-117.4zM332.8 460.8c-127.232 0-230.4 103.168-230.4 230.4s103.168 230.4 230.4 230.4c127.232 0 230.4-103.168 230.4-230.4s-103.168-230.4-230.4-230.4zM332.8 512c39.934 0 76.475 13.533 106.3 35.7l-250.4 249c-21.807-29.683-35.1-65.924-35.1-105.5 0-98.816 80.384-179.2 179.2-179.2zM477 585.7c21.785 29.674 35 65.947 35 105.5 0 98.816-80.384 179.2-179.2 179.2-39.906 0-76.386-13.561-106.2-35.7l250.4-249z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-disable"],"grid":0},"attrs":[{}],"properties":{"order":40,"id":21,"name":"document-disable","prevSize":24,"code":59669},"setIdx":2,"setId":1,"iconIdx":22},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-343.4zM716.8 189.8l117.4 117.4h-117.4v-117.4zM332.8 460.8l-230.4 256v51.2h102.4v153.6h256v-153.6h102.4v-51.2l-230.4-256zM332.8 537.3l161.5 179.5h-84.7v153.6h-153.6v-153.6h-84.7l161.5-179.5z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-publish"],"grid":0},"attrs":[{}],"properties":{"order":44,"id":22,"name":"document-publish","prevSize":24,"code":59670},"setIdx":2,"setId":1,"iconIdx":23},{"icon":{"paths":["M665.6 51.2v102.4h102.4v-102.4h-102.4zM460.8 153.6h102.4v-102.4h-102.4v102.4zM460.8 358.4h102.4v-102.4h-102.4v102.4zM665.6 358.4h102.4v-102.4h-102.4v102.4zM665.6 563.2h102.4v-102.4h-102.4v102.4zM460.8 563.2h102.4v-102.4h-102.4v102.4zM460.8 768h102.4v-102.4h-102.4v102.4zM665.6 768h102.4v-102.4h-102.4v102.4zM665.6 972.8h102.4v-102.4h-102.4v102.4zM460.8 972.8h102.4v-102.4h-102.4v102.4zM256 153.6h102.4v-102.4h-102.4v102.4zM256 358.4h102.4v-102.4h-102.4v102.4zM256 563.2h102.4v-102.4h-102.4v102.4zM256 768h102.4v-102.4h-102.4v102.4zM256 972.8h102.4v-102.4h-102.4v102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["drag"],"grid":0},"attrs":[{}],"properties":{"order":43,"id":23,"name":"drag","prevSize":24,"code":59671},"setIdx":2,"setId":1,"iconIdx":24},{"icon":{"paths":["M921.6 281.958c0-70.707-171.878-128.154-384-128.154s-384 57.19-384 127.898c0 10.035 3.789 19.712 10.342 29.030 0-0.051 296.858 406.067 296.858 406.067v256l153.6-51.2v-204.8c0 0 298.752-408.166 299.725-409.702 0 0 7.475-16.64 7.475-25.139zM537.6 204.8c206.899 0 318.208 53.248 332.083 76.8-13.875 23.552-125.184 76.8-332.083 76.8s-318.208-53.248-332.083-76.8c13.875-23.552 125.184-76.8 332.083-76.8zM869.376 345.856v0 0zM573.030 686.592c-6.4 8.755-9.83 19.354-9.83 30.208v167.885l-51.2 17.050v-184.934c0-10.854-3.43-21.453-9.83-30.208l-228.147-312.115c68.762 21.709 161.382 35.123 263.578 35.123 102.298 0 195.021-13.414 263.834-35.174-0.102 0.051-0.205 0.051-0.307 0.102l-228.096 312.064z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["filter"],"grid":0},"attrs":[{}],"properties":{"order":18,"id":24,"name":"filter","prevSize":24,"code":59672},"setIdx":2,"setId":1,"iconIdx":25},{"icon":{"paths":["M512 0c-282.88 0-512 229.248-512 512 0 226.24 146.688 418.112 350.080 485.76 25.6 4.8 35.008-11.008 35.008-24.64 0-12.16-0.448-44.352-0.64-87.040-142.464 30.912-172.48-68.672-172.48-68.672-23.296-59.136-56.96-74.88-56.96-74.88-46.4-31.744 3.584-31.104 3.584-31.104 51.392 3.584 78.4 52.736 78.4 52.736 45.696 78.272 119.872 55.68 149.12 42.56 4.608-33.088 17.792-55.68 32.448-68.48-113.728-12.8-233.216-56.832-233.216-252.992 0-55.872 19.84-101.568 52.672-137.408-5.76-12.928-23.040-64.96 4.48-135.488 0 0 42.88-13.76 140.8 52.48 40.96-11.392 84.48-17.024 128-17.28 43.52 0.256 87.040 5.888 128 17.28 97.28-66.24 140.16-52.48 140.16-52.48 27.52 70.528 10.24 122.56 5.12 135.488 32.64 35.84 52.48 81.536 52.48 137.408 0 196.672-119.68 240-233.6 252.608 17.92 15.36 34.56 46.72 34.56 94.72 0 68.48-0.64 123.52-0.64 140.16 0 13.44 8.96 29.44 35.2 24.32 204.864-67.136 351.424-259.136 351.424-485.056 0-282.752-229.248-512-512-512z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["brand","github"],"grid":0},"attrs":[{}],"properties":{"order":77,"id":25,"name":"github","prevSize":24,"code":59713},"setIdx":2,"setId":1,"iconIdx":26},{"icon":{"paths":["M512 512h-204.8v51.2h204.8v-51.2zM768 153.6h-51.2c0-28.314-22.886-51.2-51.2-51.2h-307.2c-28.314 0-51.2 22.886-51.2 51.2h-51.2c-28.314 0-51.2 22.886-51.2 51.2v665.6c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-665.6c0-28.314-22.886-51.2-51.2-51.2zM358.4 153.6h307.2v51.2h-307.2v-51.2zM768 819.2c0 28.314-22.886 51.2-51.2 51.2h-409.6c-28.314 0-51.2-22.886-51.2-51.2v-563.2c0-28.314 22.886-51.2 51.2-51.2 0 28.314 22.886 51.2 51.2 51.2h307.2c28.314 0 51.2-22.886 51.2-51.2 28.314 0 51.2 22.886 51.2 51.2v563.2zM307.2 460.8h409.6v-51.2h-409.6v51.2zM307.2 665.6h409.6v-51.2h-409.6v51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["help"],"grid":0},"attrs":[{}],"properties":{"order":19,"id":26,"name":"help","prevSize":24,"code":59673},"setIdx":2,"setId":1,"iconIdx":27},{"icon":{"paths":["M512 0c-169.421 0-307.2 137.779-307.2 307.2 0 78.643 15.258 164.915 45.261 256.41 23.859 72.55 56.986 148.582 98.56 226.099 70.707 131.635 140.339 220.774 143.309 224.512 4.813 6.195 12.288 9.779 20.070 9.779 7.834 0 15.258-3.584 20.122-9.779 2.97-3.686 72.602-92.826 143.309-224.512 41.574-77.517 74.701-153.549 98.56-226.099 29.952-91.494 45.21-177.766 45.21-256.41 0-169.421-137.83-307.2-307.2-307.2zM630.682 764.672c-46.234 86.374-92.979 154.982-118.682 190.822-25.6-35.635-72.038-103.885-118.221-189.952-62.874-117.146-137.779-291.738-137.779-458.342 0-141.158 114.842-256 256-256s256 114.842 256 256c0 166.298-74.65 340.582-137.318 457.472zM512 153.6c-84.685 0-153.6 68.915-153.6 153.6s68.915 153.6 153.6 153.6 153.6-68.915 153.6-153.6-68.915-153.6-153.6-153.6zM512 409.6c-56.525 0-102.4-45.875-102.4-102.4 0-56.474 45.875-102.4 102.4-102.4 56.474 0 102.4 45.926 102.4 102.4 0 56.525-45.926 102.4-102.4 102.4z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["location"],"grid":0},"attrs":[{}],"properties":{"order":25,"id":27,"name":"location, control-Map, type-Geolocation","prevSize":24,"code":59675},"setIdx":2,"setId":1,"iconIdx":28},{"icon":{"paths":["M512.273 83.782c-0.141 0.056-182.959 84.073-229.418 256.782-4.481 16.584 32.696 9.296 31.036 27.527-2.034 22.136-44.668 31.201-39.109 94.764 5.659 64.734 60.321 130.141 68.527 169.673v27.655c-0.497 8.54-4.566 31.715-18.018 43.036-7.378 6.19-17.322 8.421-30.436 6.782-18.205-2.275-25.449-14.468-28.345-24.309-4.753-16.218-0.322-35.123 10.345-44 10.724-8.924 12.17-24.842 3.236-35.564-8.934-10.712-24.858-12.161-35.582-3.218-25.995 21.64-36.887 61.52-26.491 97 9.815 33.392 36.197 55.884 70.6 60.182 4.903 0.609 9.566 0.909 14 0.909 26.623 0 44.661-10.175 55.582-19.455 32.866-27.97 35.449-74.593 35.636-79.818 0.009-0.309 0.018-0.618 0.018-0.927v-21.218h0.109v-1.418c0-12.351 10.008-22.364 22.382-22.364 11.944 0 21.609 9.346 22.273 21.109v202.491c-0.206 2.912-2.536 29.892-17.891 42.945-7.368 6.274-17.384 8.53-30.545 6.873-18.214-2.275-25.476-14.468-28.364-24.291-4.762-16.228-0.322-35.151 10.345-44.018 10.724-8.933 12.188-24.833 3.255-35.564-8.924-10.694-24.876-12.161-35.6-3.218-26.013 21.631-36.887 61.52-26.491 97 9.796 33.392 36.197 55.893 70.6 60.2 4.903 0.609 9.566 0.891 14 0.891 26.623 0 44.671-10.156 55.564-19.436 32.875-27.97 35.458-74.611 35.636-79.836 0.019-0.328 0.018-0.609 0.018-0.909v-225.636l0.127-0.055v-1c0-12.595 10.219-22.8 22.836-22.8 12.349 0 22.333 9.824 22.727 22.073v227.418c0 0.309-0 0.591 0.018 0.909 0.187 5.216 2.779 51.866 35.655 79.836 10.912 9.28 28.959 19.436 55.582 19.436 4.443 0 9.088-0.282 13.982-0.891 34.394-4.307 60.804-26.818 70.6-60.2 10.405-35.48-0.487-75.36-26.491-97-10.743-8.943-26.676-7.466-35.6 3.218-8.934 10.74-7.488 26.63 3.236 35.564 10.668 8.868 15.135 27.79 10.364 44.018-2.878 9.823-10.159 22.015-28.364 24.291-13.105 1.648-23.050-0.592-30.418-6.782-13.508-11.358-17.558-34.657-18.036-43v-201.818c0.297-12.093 10.14-21.818 22.327-21.818 12.374 0 22.4 10.003 22.4 22.364v1.418h0.073v21.218c0 0.318-0 0.628 0.018 0.927 0.178 5.216 2.779 51.848 35.655 79.818 10.912 9.28 28.941 19.455 55.564 19.455 4.434 0 9.107-0.292 14-0.891 34.394-4.298 60.786-26.818 70.582-60.2 10.405-35.48-0.487-75.351-26.491-97-10.743-8.933-26.667-7.476-35.582 3.236-8.943 10.722-7.488 26.622 3.236 35.545 10.668 8.877 15.117 27.8 10.345 44.018-2.878 9.842-10.159 22.025-28.364 24.291-13.086 1.648-23.050-0.583-30.418-6.764-13.508-11.368-17.549-34.675-18.018-43v-21.018c5.305-54.103 63.095-107.777 69.091-176.364 5.531-63.563-37.121-72.627-39.145-94.764-1.669-18.232 35.498-10.944 31.036-27.527-46.468-172.709-229.269-256.726-229.4-256.782z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["logo"],"grid":0},"attrs":[{}],"properties":{"order":31,"id":28,"name":"logo","prevSize":24,"code":59676},"setIdx":2,"setId":1,"iconIdx":29},{"icon":{"paths":["M947.2 0h-870.4c-42.342 0-76.8 34.458-76.8 76.8v870.4c0 42.342 34.458 76.8 76.8 76.8h870.4c42.342 0 76.8-34.458 76.8-76.8v-870.4c0-42.342-34.458-76.8-76.8-76.8zM972.8 947.2c0 14.157-11.443 25.6-25.6 25.6h-870.4c-14.131 0-25.6-11.443-25.6-25.6v-870.4c0-14.131 11.469-25.6 25.6-25.6h870.4c14.157 0 25.6 11.469 25.6 25.6v870.4zM665.6 460.8c56.448 0 102.4-45.926 102.4-102.4s-45.952-102.4-102.4-102.4c-56.448 0-102.4 45.926-102.4 102.4s45.952 102.4 102.4 102.4zM665.6 307.2c28.211 0 51.2 22.989 51.2 51.2s-22.989 51.2-51.2 51.2c-28.211 0-51.2-22.989-51.2-51.2s22.989-51.2 51.2-51.2zM896 102.4h-768c-14.131 0-25.6 11.469-25.6 25.6v614.4c0 14.157 11.469 25.6 25.6 25.6h768c14.157 0 25.6-11.443 25.6-25.6v-614.4c0-14.131-11.443-25.6-25.6-25.6zM153.6 716.8v-118.246l164.301-184.858c4.198-4.787 9.728-7.373 15.462-7.475 5.734-0.051 11.29 2.458 15.642 7.040l283.238 303.539h-478.643zM870.4 716.8h-168.090l-315.853-338.432c-14.285-15.334-33.331-23.603-53.709-23.347-20.326 0.256-39.219 9.011-53.094 24.627l-126.054 141.798v-367.846h716.8v563.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["media"],"grid":0},"attrs":[{}],"properties":{"order":30,"id":29,"name":"media, type-Assets, trigger-AssetChanged","prevSize":24,"code":59677},"setIdx":2,"setId":1,"iconIdx":30},{"icon":{"paths":["M128 384c-70.656 0-128 57.344-128 128s57.344 128 128 128c70.656 0 128-57.344 128-128s-57.344-128-128-128zM512 384c-70.656 0-128 57.344-128 128s57.344 128 128 128c70.656 0 128-57.344 128-128s-57.344-128-128-128zM896 384c-70.656 0-128 57.344-128 128s57.344 128 128 128c70.656 0 128-57.344 128-128s-57.344-128-128-128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["more"],"grid":0},"attrs":[{}],"properties":{"order":34,"id":30,"name":"more, dots","prevSize":24,"code":59678},"setIdx":2,"setId":1,"iconIdx":31},{"icon":{"paths":["M877.12 311.104l-66.304 66.368-228.224-228.224 66.368-66.368c25.216-25.152 66.048-25.152 91.264 0l136.896 137.024c25.216 25.216 25.216 65.984 0 91.2zM760.896 427.392l-386.176 386.112c-25.216 25.28-66.048 25.28-91.264 0l-136.96-136.896c-25.216-25.28-25.216-66.112 0-91.264l386.24-386.24 228.16 228.288zM64 896v-191.872l191.936 191.872h-191.936z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["pencil"],"grid":0},"attrs":[{}],"properties":{"order":47,"id":31,"name":"pencil","prevSize":24,"code":59679},"setIdx":2,"setId":1,"iconIdx":32},{"icon":{"paths":["M892.083 131.917c-73.523-73.498-193.152-73.498-266.65 0l-157.184 157.107c-9.958 10.035-9.958 26.214 0 36.275 10.061 9.984 26.24 9.984 36.25 0l157.133-157.107c53.504-53.555 140.672-53.555 194.176 0 53.581 53.504 53.581 140.672 0 194.176l-186.138 186.163c-53.53 53.581-140.672 53.581-194.176 0-10.086-10.010-26.24-10.010-36.275 0-10.035 10.086-10.035 26.189 0 36.25 36.787 36.736 84.992 55.117 133.325 55.117s96.589-18.432 133.376-55.117l186.163-186.214c73.498-73.472 73.498-193.152 0-266.65zM519.45 698.726l-157.082 157.082c-53.504 53.555-140.672 53.555-194.176 0-53.581-53.504-53.581-140.672 0-194.176l186.138-186.163c53.53-53.581 140.672-53.581 194.176 0 10.086 9.984 26.189 9.984 36.275 0 10.035-10.086 10.035-26.214 0-36.25-73.549-73.498-193.203-73.498-266.701 0l-186.163 186.163c-73.498 73.574-73.498 193.203 0 266.701 36.787 36.71 85.043 55.117 133.325 55.117 48.333 0 96.538-18.406 133.325-55.117l157.133-157.133c10.010-10.010 10.010-26.189 0-36.224-10.010-9.984-26.189-9.984-36.25 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["reference"],"grid":0},"attrs":[{}],"properties":{"order":45,"id":32,"name":"reference","prevSize":24,"code":59680},"setIdx":2,"setId":1,"iconIdx":33},{"icon":{"paths":["M800 1024h-576c-124.8 0-224-99.2-224-224v-300.8c0-124.8 99.2-224 224-224h576c124.8 0 224 99.2 224 224v300.8c0 124.8-99.2 224-224 224zM224 339.2c-89.6 0-160 70.4-160 160v300.8c0 89.6 70.4 160 160 160h576c89.6 0 160-70.4 160-160v-300.8c0-89.6-70.4-160-160-160h-576z","M828.8 201.6h-633.6c-19.2 0-32-12.8-32-32s12.8-32 32-32h630.4c19.2 0 32 12.8 32 32s-12.8 32-28.8 32z","M716.8 64h-409.6c-19.2 0-32-12.8-32-32s12.8-32 32-32h412.8c19.2 0 32 12.8 32 32s-16 32-35.2 32z","M800 416v64c0 48-38.4 83.2-83.2 83.2h-409.6c-44.8 3.2-83.2-35.2-83.2-83.2v-64h-54.4v64c0 76.8 64 140.8 140.8 140.8h406.4c76.8 0 140.8-64 140.8-140.8v-64h-57.6z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["schemas"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":46,"id":33,"name":"schemas","prevSize":24,"code":59681},"setIdx":2,"setId":1,"iconIdx":34},{"icon":{"paths":["M939.776 1003.776c-27.2 27.008-71.232 27.008-98.368 0l-168.96-168.96c-66.176 38.464-142.016 62.080-224 62.080-247.744 0-448.448-200.832-448.448-448.448 0-247.744 200.704-448.448 448.448-448.448 247.68 0 448.512 200.704 448.512 448.448 0 115.136-44.672 218.944-115.904 298.304l158.656 158.656c27.008 27.136 27.008 71.168 0.064 98.368zM448.448 128.128c-176.896 0-320.32 143.36-320.32 320.32s143.424 320.32 320.32 320.32c176.96 0 320.384-143.36 320.384-320.32s-143.488-320.32-320.384-320.32z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["search"],"grid":0},"attrs":[{}],"properties":{"order":23,"id":34,"name":"search","prevSize":24,"code":59682},"setIdx":2,"setId":1,"iconIdx":35},{"icon":{"paths":["M1019.11 440.755c-1.946-13.747-14.438-23.398-28.16-21.888-16.947 1.843-34.253-0.589-50.048-7.091-52.25-21.504-77.261-81.459-55.757-133.709 6.605-15.846 16.947-29.85 30.208-40.602 10.803-8.653 12.698-24.294 4.352-35.354-28.902-37.99-62.797-71.706-100.838-100.045-10.701-8.090-25.805-6.451-34.662 3.661-28.8 33.254-75.546 44.262-116.198 27.546-40.704-16.742-66.099-57.498-63.206-101.453 0.845-13.338-8.755-25.19-21.99-27.008-47.002-6.605-94.797-6.605-142.054 0.077-13.722 1.946-23.398 14.387-21.862 28.211 1.843 16.896-0.614 34.202-7.168 49.997-21.504 52.25-81.408 77.21-133.632 55.706-15.821-6.502-29.85-16.947-40.602-30.157-8.653-10.752-24.32-12.698-35.379-4.301-37.99 28.851-71.68 62.694-100.045 100.762-8.090 10.701-6.451 25.83 3.635 34.637 33.28 28.902 44.288 75.597 27.546 116.301-16.742 40.653-57.498 66.048-101.427 63.155-13.363-0.845-25.19 8.755-26.982 21.99-6.63 47.002-6.63 94.822 0.102 142.080 1.946 13.696 14.387 23.322 28.16 21.811 16.896-1.818 34.202 0.691 50.022 7.168 52.224 21.53 77.21 81.459 55.706 133.734-6.502 15.795-16.947 29.773-30.157 40.525-10.803 8.73-12.698 24.346-4.352 35.354 28.877 38.042 62.822 71.731 100.813 100.122 1.741 1.357 3.661 2.355 5.606 3.2 9.933 4.045 21.709 1.536 29.082-6.938 28.826-33.178 75.571-44.262 116.275-27.52 40.653 16.742 66.048 57.498 63.13 101.453-0.819 13.338 8.755 25.165 22.067 27.059 47.002 6.579 94.72 6.554 142.029-0.102 13.645-1.971 23.347-14.464 21.811-28.237-1.843-16.947 0.691-34.253 7.194-50.048 21.504-52.25 81.459-77.21 133.658-55.68 15.795 6.528 29.85 16.947 40.55 30.157 8.704 10.803 24.346 12.698 35.405 4.326 37.99-28.902 71.654-62.746 100.096-100.813 7.987-10.675 6.4-25.805-3.712-34.662-33.254-28.826-44.288-75.571-27.546-116.224 16.742-40.73 57.498-66.099 101.453-63.232 13.338 0.922 25.139-8.678 27.008-21.965 6.554-47.002 6.502-94.771-0.128-142.003zM971.059 554.010c-56.141 5.274-105.702 41.114-127.642 94.464s-12.058 113.613 24.090 156.902c-17.69 21.478-37.453 41.318-58.854 59.315-12.749-11.213-27.392-20.352-43.238-26.854-78.259-32.282-168.243 5.197-200.499 83.584-6.502 15.718-10.291 32.563-11.29 49.536-27.853 2.56-55.859 2.637-83.61 0.077-5.274-56.090-41.114-105.677-94.464-127.616-53.35-21.99-113.613-11.981-156.928 24.064-21.504-17.69-41.318-37.453-59.29-58.88 11.213-12.723 20.352-27.392 26.906-43.136 32.205-78.387-5.274-168.294-83.584-200.55-15.821-6.502-32.589-10.342-49.613-11.366-2.534-27.853-2.586-55.859 0-83.558 56.090-5.299 105.626-41.088 127.565-94.438 21.965-53.402 12.058-113.638-24.090-156.902 17.69-21.555 37.478-41.395 58.88-59.341 12.749 11.213 27.392 20.352 43.213 26.854 78.285 32.256 168.218-5.248 200.474-83.558 6.528-15.795 10.342-32.589 11.366-49.613 27.853-2.509 55.808-2.56 83.558 0 5.299 56.090 41.139 105.6 94.49 127.59 53.35 21.939 113.638 12.006 156.902-24.090 21.504 17.741 41.293 37.453 59.29 58.854-11.213 12.8-20.352 27.392-26.854 43.213-32.256 78.31 5.248 168.294 83.507 200.499 15.846 6.502 32.691 10.342 49.638 11.392 2.56 27.853 2.611 55.808 0.077 83.558zM512 307.2c-113.101 0-204.8 91.699-204.8 204.8 0 113.126 91.699 204.826 204.8 204.826s204.8-91.699 204.8-204.826c0-113.101-91.699-204.8-204.8-204.8zM512 665.626c-84.813 0-153.6-68.813-153.6-153.626 0-84.838 68.787-153.6 153.6-153.6 84.838 0 153.6 68.762 153.6 153.6 0 84.813-68.762 153.626-153.6 153.626z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["settings"],"grid":0},"attrs":[{}],"properties":{"order":22,"id":35,"name":"settings","prevSize":24,"code":59683},"setIdx":2,"setId":1,"iconIdx":36},{"icon":{"paths":["M77.005 102.605h128v332.8c0 14.131 11.418 25.6 25.6 25.6 14.106 0 25.6-11.469 25.6-25.6v-332.8h128c14.106 0 25.6-11.469 25.6-25.6 0-14.157-11.494-25.6-25.6-25.6h-307.2c-14.182 0-25.6 11.443-25.6 25.6 0 14.106 11.418 25.6 25.6 25.6zM947.405 716.979h-179.2v-102.4h179.2c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-204.8c-14.182 0-25.6 11.443-25.6 25.6v358.4c0 14.157 11.418 25.6 25.6 25.6 14.157 0 25.6-11.443 25.6-25.6v-179.2h179.2c14.157 0 25.6-11.443 25.6-25.6s-11.494-25.6-25.6-25.6zM965.094 58.47c-9.958-9.933-26.112-9.933-36.045 0l-870.605 870.579c-9.958 9.984-9.958 26.086 0 36.045 10.010 9.984 26.112 9.984 36.045 0l870.605-870.579c9.958-9.933 9.958-26.086 0-36.045z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-boolean"],"grid":0},"attrs":[{}],"properties":{"order":21,"id":36,"name":"type-Boolean","prevSize":24,"code":59684},"setIdx":2,"setId":1,"iconIdx":37},{"icon":{"paths":["M947.2 102.4h-128v-25.6c0-14.131-11.469-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-512v-25.6c0-14.131-11.52-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-128c-42.342 0-76.8 34.458-76.8 76.8v716.8c0 42.342 34.458 76.8 76.8 76.8h870.4c42.342 0 76.8-34.458 76.8-76.8v-716.8c0-42.342-34.458-76.8-76.8-76.8zM972.8 896c0 14.131-11.469 25.6-25.6 25.6h-870.4c-14.080 0-25.6-11.469-25.6-25.6v-537.6h921.6v537.6zM972.8 307.2h-921.6v-128c0-14.080 11.52-25.6 25.6-25.6h128v76.8c0 14.080 11.52 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h512v76.8c0 14.080 11.469 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h128c14.131 0 25.6 11.52 25.6 25.6v128zM332.8 512h51.2c14.080 0 25.6-11.52 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM640 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-datetime"],"grid":0},"attrs":[{}],"properties":{"order":24,"id":37,"name":"type-DateTime","prevSize":24,"code":59685},"setIdx":2,"setId":1,"iconIdx":38},{"icon":{"paths":["M179.2 256c0-28.262 22.938-51.2 51.2-51.2h25.6c14.157 0 25.6-11.443 25.6-25.6 0-14.131-11.443-25.6-25.6-25.6h-25.6c-56.55 0-102.4 45.85-102.4 102.4v179.2c0 28.262-22.938 51.2-51.2 51.2h-25.6c-14.157 0-25.6 11.469-25.6 25.6 0 14.157 11.443 25.6 25.6 25.6h25.6c28.262 0 51.2 22.938 51.2 51.2v179.2c0 56.55 45.85 102.4 102.4 102.4h25.6c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-25.6c-28.262 0-51.2-22.938-51.2-51.2v-179.2c0-30.746-13.85-58.061-35.328-76.8 21.478-18.765 35.328-46.029 35.328-76.8v-179.2zM972.8 486.4h-25.6c-28.262 0-51.2-22.938-51.2-51.2v-179.2c0-56.55-45.85-102.4-102.4-102.4h-25.6c-14.157 0-25.6 11.469-25.6 25.6 0 14.157 11.443 25.6 25.6 25.6h25.6c28.262 0 51.2 22.938 51.2 51.2v179.2c0 30.771 13.85 58.035 35.328 76.8-21.478 18.739-35.328 46.054-35.328 76.8v179.2c0 28.262-22.938 51.2-51.2 51.2h-25.6c-14.157 0-25.6 11.443-25.6 25.6s11.443 25.6 25.6 25.6h25.6c56.55 0 102.4-45.85 102.4-102.4v-179.2c0-28.262 22.938-51.2 51.2-51.2h25.6c14.157 0 25.6-11.443 25.6-25.6 0-14.131-11.443-25.6-25.6-25.6zM512 332.8c-14.157 0-25.6 11.469-25.6 25.6 0 14.157 11.443 25.6 25.6 25.6s25.6-11.443 25.6-25.6c0-14.131-11.443-25.6-25.6-25.6zM512 435.2c-14.157 0-25.6 11.469-25.6 25.6v204.8c0 14.157 11.443 25.6 25.6 25.6s25.6-11.443 25.6-25.6v-204.8c0-14.131-11.443-25.6-25.6-25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["json"],"grid":0},"attrs":[{}],"properties":{"order":20,"id":38,"name":"type-Json, json","prevSize":24,"code":59674},"setIdx":2,"setId":1,"iconIdx":39},{"icon":{"paths":["M256 665.6h-76.8v-332.8c0-14.131-11.469-25.6-25.6-25.6h-76.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h51.2v307.2h-76.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h204.8c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6zM614.4 307.2h-204.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h179.2v128h-179.2c-14.131 0-25.6 11.469-25.6 25.6v179.2c0 14.131 11.469 25.6 25.6 25.6h204.8c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-179.2v-128h179.2c14.131 0 25.6-11.469 25.6-25.6v-179.2c0-14.131-11.469-25.6-25.6-25.6zM972.8 307.2h-204.8c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h179.2v128h-179.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h179.2v128h-179.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6h204.8c14.131 0 25.6-11.469 25.6-25.6v-358.4c0-14.131-11.469-25.6-25.6-25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-number"],"grid":0},"attrs":[{}],"properties":{"order":32,"id":39,"name":"type-Number","prevSize":24,"code":59686},"setIdx":2,"setId":1,"iconIdx":40},{"icon":{"paths":["M870.4 921.6h-716.8c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h716.8c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6zM194.688 817.152c13.030 5.555 28.083-0.461 33.613-13.44l125.030-291.712h317.338l125.005 291.712c4.173 9.677 13.568 15.488 23.526 15.488 3.405 0 6.81-0.64 10.112-2.048 13.005-5.606 18.995-20.659 13.44-33.638l-131.61-306.944c-0.051-0.051-0.051-0.154-0.102-0.205l-175.488-409.6c-4.045-9.472-13.312-15.565-23.552-15.565s-19.507 6.093-23.552 15.514l-175.488 409.6c-0.051 0.051-0.051 0.154-0.102 0.205l-131.61 306.97c-5.53 13.005 0.461 28.058 13.44 33.664zM512 141.773l136.704 319.027h-273.408l136.704-319.027z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-string"],"grid":0},"attrs":[{}],"properties":{"order":48,"id":40,"name":"type-String","prevSize":24,"code":59687},"setIdx":2,"setId":1,"iconIdx":41},{"icon":{"paths":["M955.221 848c0-0.109 10.752 0 0 0-52.751-161.392-240.461-224-443.178-224-202.269 0-389.979 63.392-443.066 224-11.2-0.109 0-1.232 0 0 0 61.936 49.615 112 110.654 112h664.823c61.151 0 110.766-50.064 110.766-112zM290.399 288c0 123.648 99.231 336 221.645 336s221.645-212.352 221.645-336c0-123.648-99.231-224-221.645-224s-221.645 100.352-221.645 224z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["user"],"grid":0},"attrs":[{}],"properties":{"order":33,"id":41,"name":"user","prevSize":24,"code":59688},"setIdx":2,"setId":1,"iconIdx":42},{"icon":{"paths":["M469.333 614.997v281.003c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-281.003l97.835 97.835c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-170.667-170.667c-0.085-0.085-0.171-0.171-0.256-0.256-4.053-3.968-8.661-6.955-13.568-9.003-5.12-2.133-10.624-3.2-16.085-3.243-0.171 0-0.341 0-0.469 0-5.461 0.043-10.965 1.109-16.085 3.243-4.949 2.048-9.557 5.035-13.568 9.003-0.085 0.085-0.171 0.171-0.256 0.256l-170.667 170.667c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0zM890.411 822.101c30.379-16.555 56.149-38.443 76.672-63.915 21.333-26.411 36.949-56.619 46.379-88.576s12.629-65.835 9.003-99.584c-3.456-32.512-13.269-64.896-29.824-95.232-14.208-26.069-32.384-48.768-53.376-67.669-21.717-19.541-46.421-34.944-72.875-45.952-30.891-12.8-64.171-19.584-98.048-19.84h-22.528c-13.312-37.717-32.085-72.235-55.168-102.912-30.635-40.661-68.821-74.453-111.915-99.84s-91.179-42.411-141.568-49.536c-48.597-6.784-99.243-4.395-149.504 8.619s-95.744 35.413-134.912 64.939c-40.661 30.635-74.453 68.821-99.84 111.915s-42.411 91.179-49.493 141.568c-6.827 48.555-4.395 99.2 8.576 149.461 15.872 61.312 45.781 115.627 84.267 158.421 15.744 17.536 42.752 18.944 60.245 3.2s18.944-42.752 3.2-60.245c-29.355-32.64-52.693-74.667-65.109-122.752-10.155-39.253-11.989-78.592-6.699-116.224 5.504-39.125 18.773-76.501 38.571-110.123s46.080-63.317 77.653-87.083c30.379-22.869 65.664-40.32 104.917-50.475s78.592-11.989 116.224-6.699c39.125 5.504 76.544 18.731 110.123 38.528s63.317 46.080 87.083 77.653c22.869 30.379 40.32 65.664 50.475 104.917 4.907 18.56 21.547 32 41.301 32h53.461c22.869 0.171 45.269 4.736 65.92 13.312 17.707 7.339 34.133 17.621 48.512 30.592 13.909 12.501 25.984 27.605 35.541 45.099 11.093 20.352 17.579 41.899 19.883 63.488 2.389 22.443 0.256 45.013-6.016 66.432s-16.725 41.515-30.933 59.093c-13.611 16.896-30.763 31.445-51.115 42.581-20.693 11.264-28.331 37.205-17.024 57.899s37.205 28.331 57.899 17.024z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["upload-cloud"],"grid":0},"attrs":[{}],"properties":{"order":1,"id":2,"prevSize":24,"code":59763,"name":"upload-3"},"setIdx":2,"setId":1,"iconIdx":43},{"icon":{"paths":["M853.333 640v170.667c0 5.845-1.152 11.349-3.2 16.299-2.133 5.205-5.333 9.899-9.301 13.867s-8.661 7.125-13.867 9.301c-4.949 2.048-10.453 3.2-16.299 3.2h-597.333c-5.845 0-11.349-1.152-16.299-3.2-5.205-2.133-9.899-5.333-13.867-9.301s-7.125-8.661-9.301-13.867c-2.048-4.949-3.2-10.453-3.2-16.299v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v170.667c0 17.28 3.456 33.835 9.728 48.981 6.485 15.701 16 29.781 27.776 41.557s25.856 21.291 41.557 27.776c15.104 6.229 31.659 9.685 48.939 9.685h597.333c17.28 0 33.835-3.456 48.981-9.728 15.701-6.485 29.781-16 41.557-27.776s21.291-25.856 27.776-41.557c6.229-15.104 9.685-31.659 9.685-48.939v-170.667c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667zM469.333 230.997v409.003c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-409.003l140.501 140.501c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-213.333-213.333c-0.043-0.043-0.128-0.085-0.171-0.171-4.053-4.011-8.704-7.040-13.653-9.088-10.453-4.309-22.229-4.309-32.683 0-4.949 2.048-9.6 5.077-13.653 9.088-0.043 0.043-0.128 0.085-0.171 0.171l-213.333 213.333c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["upload"],"grid":0},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":24,"code":59761,"name":"upload-4"},"setIdx":2,"setId":1,"iconIdx":44},{"icon":{"paths":["M621.254 877.254l320-320c24.994-24.992 24.994-65.516 0-90.51l-320-320c-24.994-24.992-65.516-24.992-90.51 0-24.994 24.994-24.994 65.516 0 90.51l210.746 210.746h-613.49c-35.346 0-64 28.654-64 64s28.654 64 64 64h613.49l-210.746 210.746c-12.496 12.496-18.744 28.876-18.744 45.254s6.248 32.758 18.744 45.254c24.994 24.994 65.516 24.994 90.51 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["arrow-right","right","next"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":32,"code":59766,"name":"arrow-right"},"setIdx":2,"setId":1,"iconIdx":58},{"icon":{"paths":["M448 576h128v-256h192l-256-256-256 256h192zM640 432v98.712l293.066 109.288-421.066 157.018-421.066-157.018 293.066-109.288v-98.712l-384 144v256l512 192 512-192v-256z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["upload","load","arrow"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":32,"code":59760,"name":"upload"},"setIdx":2,"setId":1,"iconIdx":59},{"icon":{"paths":["M585.143 548.557c0 9.728-3.986 18.871-10.862 25.71l-256 256c-6.839 6.839-16.018 10.862-25.71 10.862s-18.871-3.986-25.71-10.862l-256-256c-6.839-6.839-10.862-16.018-10.862-25.71 0-20.005 16.567-36.571 36.571-36.571h512c20.005 0 36.571 16.567 36.571 36.571z","M585.143 219.443c0 9.728-3.986 18.871-10.862 25.71l-256 256c-6.839 6.839-16.018 10.862-25.71 10.862s-18.871-3.986-25.71-10.862l-256-256c-6.839-6.839-10.862-16.018-10.862-25.71 0-20.005 16.567-36.571 36.571-36.571h512c20.005 0 36.571 16.567 36.571 36.571z"],"width":585,"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-bottom"],"grid":16},"attrs":[{},{}],"properties":{"order":125,"id":0,"name":"caret-bottom","prevSize":32,"code":59755},"setIdx":2,"setId":1,"iconIdx":60},{"icon":{"paths":["M585.143 804.577c0 20.005-16.567 36.571-36.571 36.571h-512c-20.005 0-36.571-16.567-36.571-36.571 0-9.728 3.986-18.871 10.862-25.71l256-256c6.839-6.839 16.018-10.862 25.71-10.862s18.871 3.986 25.71 10.862l256 256c6.839 6.839 10.862 16.018 10.862 25.71z","M585.143 475.423c0 20.005-16.567 36.571-36.571 36.571h-512c-20.005 0-36.571-16.567-36.571-36.571 0-9.728 3.986-18.871 10.862-25.71l256-256c6.839-6.839 16.018-10.862 25.71-10.862s18.871 3.986 25.71 10.862l256 256c6.839 6.839 10.862 16.018 10.862 25.71z"],"width":585,"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-top"],"grid":16},"attrs":[{},{}],"properties":{"order":124,"id":1,"name":"caret-top","prevSize":32,"code":59756},"setIdx":2,"setId":1,"iconIdx":61},{"icon":{"paths":["M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M408.906 587.72l-35.3-37 138.1-131.9 138 131.9-35.3 37-102.7-98.1z","M511.706 773.12l-138.1-131.9 35.3-37 102.8 98.1 102.7-98.1 35.3 37z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["show"],"grid":16},"attrs":[{},{},{}],"properties":{"order":123,"id":2,"name":"show","prevSize":32,"code":59748},"setIdx":2,"setId":1,"iconIdx":62},{"icon":{"paths":["M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M348.394 15.988c-28.314 0-51.2 22.886-51.2 51.2v23.7h51.2v-23.7h307.2l204.8 204.8v512h-23.8v51.2h23.8c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2z","M408.906 587.72l-35.3-37 138.1-131.9 138 131.9-35.3 37-102.7-98.1z","M511.706 773.12l-138.1-131.9 35.3-37 102.8 98.1 102.7-98.1 35.3 37z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["show-all"],"grid":16},"attrs":[{},{},{},{}],"properties":{"order":122,"id":3,"name":"show-all","prevSize":32,"code":59749},"setIdx":2,"setId":1,"iconIdx":63},{"icon":{"paths":["M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M408.9 418.8l-35.3 37 138 131.9 138.1-131.9-35.3-37-102.8 98.1z","M511.6 604.2l-138 131.9 35.3 37 102.7-98.1 102.8 98.1 35.3-37z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["hide"],"grid":16},"attrs":[{},{},{}],"properties":{"order":121,"id":4,"name":"hide","prevSize":32,"code":59750},"setIdx":2,"setId":1,"iconIdx":64},{"icon":{"paths":["M408.9 418.8l-35.3 37 138.1 131.9 138-131.9-35.3-37-102.7 98.1z","M511.7 604.2l-138.1 131.9 35.3 37 102.8-98.1 102.7 98.1 35.3-37z","M256 102.4c-28.314 0-51.2 22.886-51.2 51.2v256h51.2v-256h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-512v-460.8h-51.2v460.8c0 28.314 22.886 51.2 51.2 51.2h512c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM614.4 189.8l117.4 117.4h-117.4z","M348.394 15.988c-28.314 0-51.2 22.886-51.2 51.2v23.7h51.2v-23.7h307.2l204.8 204.8v512h-23.8v51.2h23.8c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["hide-all"],"grid":16},"attrs":[{},{},{},{}],"properties":{"order":120,"id":5,"name":"hide-all","prevSize":32,"code":59751},"setIdx":2,"setId":1,"iconIdx":65},{"icon":{"paths":["M512 1024c-136.76 0-265.334-53.258-362.040-149.96-96.702-96.706-149.96-225.28-149.96-362.040 0-96.838 27.182-191.134 78.606-272.692 50-79.296 120.664-143.372 204.356-185.3l43 85.832c-68.038 34.084-125.492 86.186-166.15 150.67-41.746 66.208-63.812 142.798-63.812 221.49 0 229.382 186.618 416 416 416s416-186.618 416-416c0-78.692-22.066-155.282-63.81-221.49-40.66-64.484-98.114-116.584-166.15-150.67l43-85.832c83.692 41.928 154.358 106.004 204.356 185.3 51.422 81.558 78.604 175.854 78.604 272.692 0 136.76-53.258 265.334-149.96 362.040-96.706 96.702-225.28 149.96-362.040 149.96z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["spinner","loading","loading-wheel","busy","wait"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":6,"prevSize":32,"code":59737,"name":"spinner2"},"setIdx":2,"setId":1,"iconIdx":66},{"icon":{"paths":["M1024 397.050l-353.78-51.408-158.22-320.582-158.216 320.582-353.784 51.408 256 249.538-60.432 352.352 316.432-166.358 316.432 166.358-60.434-352.352 256.002-249.538z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["star-full","rate","star","favorite","bookmark"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":7,"prevSize":32,"code":59741,"name":"star-full"},"setIdx":2,"setId":1,"iconIdx":67},{"icon":{"paths":["M1024 397.050l-353.78-51.408-158.22-320.582-158.216 320.582-353.784 51.408 256 249.538-60.432 352.352 316.432-166.358 316.432 166.358-60.434-352.352 256.002-249.538zM512 753.498l-223.462 117.48 42.676-248.83-180.786-176.222 249.84-36.304 111.732-226.396 111.736 226.396 249.836 36.304-180.788 176.222 42.678 248.83-223.462-117.48z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["star-empty","rate","star","favorite","bookmark"],"grid":16},"attrs":[{}],"properties":{"order":2,"id":8,"prevSize":32,"code":59742,"name":"star-empty"},"setIdx":2,"setId":1,"iconIdx":68},{"icon":{"paths":["M1024 226.4c-37.6 16.8-78.2 28-120.6 33 43.4-26 76.6-67.2 92.4-116.2-40.6 24-85.6 41.6-133.4 51-38.4-40.8-93-66.2-153.4-66.2-116 0-210 94-210 210 0 16.4 1.8 32.4 5.4 47.8-174.6-8.8-329.4-92.4-433-219.6-18 31-28.4 67.2-28.4 105.6 0 72.8 37 137.2 93.4 174.8-34.4-1-66.8-10.6-95.2-26.2 0 0.8 0 1.8 0 2.6 0 101.8 72.4 186.8 168.6 206-17.6 4.8-36.2 7.4-55.4 7.4-13.6 0-26.6-1.4-39.6-3.8 26.8 83.4 104.4 144.2 196.2 146-72 56.4-162.4 90-261 90-17 0-33.6-1-50.2-3 93.2 59.8 203.6 94.4 322.2 94.4 386.4 0 597.8-320.2 597.8-597.8 0-9.2-0.2-18.2-0.6-27.2 41-29.4 76.6-66.4 104.8-108.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["twitter","brand","tweet","social"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":9,"prevSize":32,"code":59740,"name":"twitter"},"setIdx":2,"setId":1,"iconIdx":69},{"icon":{"paths":["M728.992 512c137.754-87.334 231.008-255.208 231.008-448 0-21.676-1.192-43.034-3.478-64h-889.042c-2.29 20.968-3.48 42.326-3.48 64 0 192.792 93.254 360.666 231.006 448-137.752 87.334-231.006 255.208-231.006 448 0 21.676 1.19 43.034 3.478 64h889.042c2.288-20.966 3.478-42.324 3.478-64 0.002-192.792-93.252-360.666-231.006-448zM160 960c0-186.912 80.162-345.414 224-397.708v-100.586c-143.838-52.29-224-210.792-224-397.706v0h704c0 186.914-80.162 345.416-224 397.706v100.586c143.838 52.294 224 210.796 224 397.708h-704zM619.626 669.594c-71.654-40.644-75.608-93.368-75.626-125.366v-64.228c0-31.994 3.804-84.914 75.744-125.664 38.504-22.364 71.808-56.348 97.048-98.336h-409.582c25.266 42.032 58.612 76.042 97.166 98.406 71.654 40.644 75.606 93.366 75.626 125.366v64.228c0 31.992-3.804 84.914-75.744 125.664-72.622 42.18-126.738 125.684-143.090 226.336h501.67c-16.364-100.708-70.53-184.248-143.212-226.406z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["hour-glass","loading","busy","wait"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":10,"prevSize":32,"code":59732,"name":"hour-glass"},"setIdx":2,"setId":1,"iconIdx":70},{"icon":{"paths":["M192 512c0-12.18 0.704-24.196 2.030-36.022l-184.98-60.104c-5.916 31.14-9.050 63.264-9.050 96.126 0 147.23 62.166 279.922 161.654 373.324l114.284-157.296c-52.124-56.926-83.938-132.758-83.938-216.028zM832 512c0 83.268-31.812 159.102-83.938 216.028l114.284 157.296c99.488-93.402 161.654-226.094 161.654-373.324 0-32.862-3.132-64.986-9.048-96.126l-184.98 60.104c1.324 11.828 2.028 23.842 2.028 36.022zM576 198.408c91.934 18.662 169.544 76.742 214.45 155.826l184.978-60.102c-73.196-155.42-222.24-268.060-399.428-290.156v194.432zM233.55 354.232c44.906-79.084 122.516-137.164 214.45-155.826v-194.43c-177.188 22.096-326.23 134.736-399.426 290.154l184.976 60.102zM644.556 803.328c-40.39 18.408-85.272 28.672-132.556 28.672s-92.166-10.264-132.554-28.67l-114.292 157.31c73.206 40.366 157.336 63.36 246.846 63.36s173.64-22.994 246.848-63.36l-114.292-157.312z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["spinner","loading","loading-wheel","busy","wait"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":11,"prevSize":32,"code":59731,"name":"spinner"},"setIdx":2,"setId":1,"iconIdx":71},{"icon":{"paths":["M658.744 749.256l-210.744-210.746v-282.51h128v229.49l173.256 173.254zM512 0c-282.77 0-512 229.23-512 512s229.23 512 512 512 512-229.23 512-512-229.23-512-512-512zM512 896c-212.078 0-384-171.922-384-384s171.922-384 384-384c212.078 0 384 171.922 384 384s-171.922 384-384 384z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["clock","time","schedule"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":12,"prevSize":32,"code":59728,"name":"clock"},"setIdx":2,"setId":1,"iconIdx":72},{"icon":{"paths":["M128 320v640c0 35.2 28.8 64 64 64h576c35.2 0 64-28.8 64-64v-640h-704zM320 896h-64v-448h64v448zM448 896h-64v-448h64v448zM576 896h-64v-448h64v448zM704 896h-64v-448h64v448z","M848 128h-208v-80c0-26.4-21.6-48-48-48h-224c-26.4 0-48 21.6-48 48v80h-208c-26.4 0-48 21.6-48 48v80h832v-80c0-26.4-21.6-48-48-48zM576 128h-192v-63.198h192v63.198z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["bin","trashcan","remove","delete","recycle","dispose"],"grid":16},"attrs":[{},{}],"properties":{"order":1,"id":13,"name":"bin2","prevSize":32,"code":59650},"setIdx":2,"setId":1,"iconIdx":73},{"icon":{"paths":["M512 0c-282.77 0-512 229.23-512 512s229.23 512 512 512 512-229.23 512-512-229.23-512-512-512zM512 960.002c-62.958 0-122.872-13.012-177.23-36.452l233.148-262.29c5.206-5.858 8.082-13.422 8.082-21.26v-96c0-17.674-14.326-32-32-32-112.99 0-232.204-117.462-233.374-118.626-6-6.002-14.14-9.374-22.626-9.374h-128c-17.672 0-32 14.328-32 32v192c0 12.122 6.848 23.202 17.69 28.622l110.31 55.156v187.886c-116.052-80.956-192-215.432-192-367.664 0-68.714 15.49-133.806 43.138-192h116.862c8.488 0 16.626-3.372 22.628-9.372l128-128c6-6.002 9.372-14.14 9.372-22.628v-77.412c40.562-12.074 83.518-18.588 128-18.588 70.406 0 137.004 16.26 196.282 45.2-4.144 3.502-8.176 7.164-12.046 11.036-36.266 36.264-56.236 84.478-56.236 135.764s19.97 99.5 56.236 135.764c36.434 36.432 85.218 56.264 135.634 56.26 3.166 0 6.342-0.080 9.518-0.236 13.814 51.802 38.752 186.656-8.404 372.334-0.444 1.744-0.696 3.488-0.842 5.224-81.324 83.080-194.7 134.656-320.142 134.656z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["earth","globe","language","web","internet","sphere","planet"],"defaultCode":59850,"grid":16},"attrs":[],"properties":{"ligatures":"earth, globe2","name":"earth","id":14,"order":91,"prevSize":32,"code":59850},"setIdx":2,"setId":1,"iconIdx":74},{"icon":{"paths":["M512.002 193.212v-65.212h128v-64c0-35.346-28.654-64-64.002-64h-191.998c-35.346 0-64 28.654-64 64v64h128v65.212c-214.798 16.338-384 195.802-384 414.788 0 229.75 186.25 416 416 416s416-186.25 416-416c0-218.984-169.202-398.448-384-414.788zM706.276 834.274c-60.442 60.44-140.798 93.726-226.274 93.726s-165.834-33.286-226.274-93.726c-60.44-60.44-93.726-140.8-93.726-226.274s33.286-165.834 93.726-226.274c58.040-58.038 134.448-91.018 216.114-93.548l-21.678 314.020c-1.86 26.29 12.464 37.802 31.836 37.802s33.698-11.512 31.836-37.802l-21.676-314.022c81.666 2.532 158.076 35.512 216.116 93.55 60.44 60.44 93.726 140.8 93.726 226.274s-33.286 165.834-93.726 226.274z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["stopwatch","time","speed","meter","chronometer"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":15,"prevSize":32,"code":59715,"name":"elapsed"},"setIdx":2,"setId":1,"iconIdx":75},{"icon":{"paths":["M522.2 438.8v175.6h290.4c-11.8 75.4-87.8 220.8-290.4 220.8-174.8 0-317.4-144.8-317.4-323.2s142.6-323.2 317.4-323.2c99.4 0 166 42.4 204 79l139-133.8c-89.2-83.6-204.8-134-343-134-283 0-512 229-512 512s229 512 512 512c295.4 0 491.6-207.8 491.6-500.2 0-33.6-3.6-59.2-8-84.8l-483.6-0.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["google","brand"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":16,"prevSize":32,"code":59707,"name":"google"},"setIdx":2,"setId":1,"iconIdx":76},{"icon":{"paths":["M592 448h-16v-192c0-105.87-86.13-192-192-192h-128c-105.87 0-192 86.13-192 192v192h-16c-26.4 0-48 21.6-48 48v480c0 26.4 21.6 48 48 48h544c26.4 0 48-21.6 48-48v-480c0-26.4-21.6-48-48-48zM192 256c0-35.29 28.71-64 64-64h128c35.29 0 64 28.71 64 64v192h-256v-192z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lock","secure","private","encrypted"],"grid":16},"attrs":[{}],"properties":{"order":2,"id":17,"prevSize":32,"code":59700,"name":"lock"},"setIdx":2,"setId":1,"iconIdx":77},{"icon":{"paths":["M0.35 512l-0.35-312.074 384-52.144v364.218zM448 138.482l511.872-74.482v448h-511.872zM959.998 576l-0.126 448-511.872-72.016v-375.984zM384 943.836l-383.688-52.594-0.020-315.242h383.708z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["windows8","brand","os"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":18,"prevSize":32,"code":59712,"name":"microsoft"},"setIdx":2,"setId":1,"iconIdx":78},{"icon":{"paths":["M128 128h320v768h-320zM576 128h320v768h-320z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["pause","player"],"grid":16},"attrs":[{}],"properties":{"order":2,"id":19,"prevSize":32,"code":59695,"name":"pause"},"setIdx":2,"setId":1,"iconIdx":79},{"icon":{"paths":["M192 128l640 384-640 384z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["play","player"],"grid":16},"attrs":[{}],"properties":{"order":3,"id":20,"prevSize":32,"code":59696,"name":"play"},"setIdx":2,"setId":1,"iconIdx":80},{"icon":{"paths":["M889.68 166.32c-93.608-102.216-228.154-166.32-377.68-166.32-282.77 0-512 229.23-512 512h96c0-229.75 186.25-416 416-416 123.020 0 233.542 53.418 309.696 138.306l-149.696 149.694h352v-352l-134.32 134.32z","M928 512c0 229.75-186.25 416-416 416-123.020 0-233.542-53.418-309.694-138.306l149.694-149.694h-352v352l134.32-134.32c93.608 102.216 228.154 166.32 377.68 166.32 282.77 0 512-229.23 512-512h-96z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["loop","repeat","player","reload","refresh","update","synchronize","arrows"],"grid":16},"attrs":[{},{}],"properties":{"order":49,"id":21,"prevSize":32,"code":59694,"name":"reset"},"setIdx":2,"setId":1,"iconIdx":81},{"icon":{"paths":["M933.79 610.25c-53.726-93.054-21.416-212.304 72.152-266.488l-100.626-174.292c-28.75 16.854-62.176 26.518-97.846 26.518-107.536 0-194.708-87.746-194.708-195.99h-201.258c0.266 33.41-8.074 67.282-25.958 98.252-53.724 93.056-173.156 124.702-266.862 70.758l-100.624 174.292c28.97 16.472 54.050 40.588 71.886 71.478 53.638 92.908 21.512 211.92-71.708 266.224l100.626 174.292c28.65-16.696 61.916-26.254 97.4-26.254 107.196 0 194.144 87.192 194.7 194.958h201.254c-0.086-33.074 8.272-66.57 25.966-97.218 53.636-92.906 172.776-124.594 266.414-71.012l100.626-174.29c-28.78-16.466-53.692-40.498-71.434-71.228zM512 719.332c-114.508 0-207.336-92.824-207.336-207.334 0-114.508 92.826-207.334 207.336-207.334 114.508 0 207.332 92.826 207.332 207.334-0.002 114.51-92.824 207.334-207.332 207.334z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["cog","gear","preferences","settings","generate","control","options"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":22,"prevSize":32,"code":59693,"name":"settings2"},"setIdx":2,"setId":1,"iconIdx":82},{"icon":{"paths":["M512 128c-247.424 0-448 200.576-448 448s200.576 448 448 448 448-200.576 448-448-200.576-448-448-448zM512 936c-198.824 0-360-161.178-360-360 0-198.824 161.176-360 360-360 198.822 0 360 161.176 360 360 0 198.822-161.178 360-360 360zM934.784 287.174c16.042-28.052 25.216-60.542 25.216-95.174 0-106.040-85.96-192-192-192-61.818 0-116.802 29.222-151.92 74.596 131.884 27.236 245.206 105.198 318.704 212.578v0zM407.92 74.596c-35.116-45.374-90.102-74.596-151.92-74.596-106.040 0-192 85.96-192 192 0 34.632 9.174 67.122 25.216 95.174 73.5-107.38 186.822-185.342 318.704-212.578z","M512 576v-256h-64v320h256v-64z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["alarm","time","clock"],"grid":16},"attrs":[{},{}],"properties":{"order":2,"id":23,"prevSize":32,"code":59716,"name":"timeout"},"setIdx":2,"setId":1,"iconIdx":83},{"icon":{"paths":["M768 64c105.87 0 192 86.13 192 192v192h-128v-192c0-35.29-28.71-64-64-64h-128c-35.29 0-64 28.71-64 64v192h16c26.4 0 48 21.6 48 48v480c0 26.4-21.6 48-48 48h-544c-26.4 0-48-21.6-48-48v-480c0-26.4 21.6-48 48-48h400v-192c0-105.87 86.13-192 192-192h128z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["unlocked","lock-open"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":24,"prevSize":32,"code":59699,"name":"unlocked"},"setIdx":2,"setId":1,"iconIdx":84},{"icon":{"paths":["M832 416h-320v64h-64v-96h384v-192h-32v96c0 17.664-14.336 32-32 32h-576c-17.696 0-32-14.336-32-32v-128c0-17.696 14.304-32 32-32h576c17.664 0 32 14.304 32 32h64v256h-32zM736 160h-512v32h512v-32zM544 832c0 35.328-28.672 64-64 64s-64-28.672-64-64v-320h128v320zM480 786.656c-17.696 0-32 14.336-32 32 0 17.696 14.304 32 32 32 17.664 0 32-14.304 32-32 0-17.664-14.336-32-32-32z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["paint","tool"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":32,"code":59725,"name":"control-Color"},"setIdx":2,"setId":1,"iconIdx":85},{"icon":{"paths":["M1328 320c-8.832 0-16 7.168-16 16v640c0 8.832-7.168 16-16 16h-1248c-8.832 0-16-7.168-16-16v-640c0-8.832-7.168-16-16-16s-16 7.168-16 16v640c0 26.464 21.536 48 48 48h1248c26.464 0 48-21.536 48-48v-640c0-8.832-7.168-16-16-16zM1296 0h-1248c-26.464 0-48 21.536-48 48v192c0 8.832 7.168 16 16 16h1312c8.832 0 16-7.168 16-16v-192c0-26.464-21.536-48-48-48zM1312 224h-1280v-176c0-8.832 7.168-16 16-16h1248c8.832 0 16 7.168 16 16v176zM560 896c8.832 0 16-7.168 16-16v-512c0-8.832-7.168-16-16-16h-416c-8.832 0-16 7.168-16 16v512c0 8.832 7.168 16 16 16h416zM160 384h384v480h-384v-480zM720 480h480c8.832 0 16-7.168 16-16s-7.168-16-16-16h-480c-8.832 0-16 7.168-16 16s7.168 16 16 16zM720 640h480c8.832 0 16-7.168 16-16s-7.168-16-16-16h-480c-8.832 0-16 7.168-16 16s7.168 16 16 16zM720 800h480c8.832 0 16-7.168 16-16s-7.168-16-16-16h-480c-8.832 0-16 7.168-16 16s7.168 16 16 16zM96 128c0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32s-32 14.327-32 32zM224 128c0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32s-32 14.327-32 32zM352 128c0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32s-32 14.327-32 32z"],"width":1344,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["browser","window","software","program"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":1,"prevSize":32,"code":59701,"name":"browser"},"setIdx":2,"setId":1,"iconIdx":86},{"icon":{"paths":["M927.936 272.992l-68.288-68.288c-12.608-12.576-32.96-12.576-45.536 0l-409.44 409.44-194.752-196.16c-12.576-12.576-32.928-12.576-45.536 0l-68.288 68.288c-12.576 12.608-12.576 32.96 0 45.536l285.568 287.488c12.576 12.576 32.96 12.576 45.536 0l500.736-500.768c12.576-12.544 12.576-32.96 0-45.536z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["checkmark","tick","approve","submit"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":2,"prevSize":32,"code":59714,"name":"checkmark"},"setIdx":2,"setId":1,"iconIdx":87},{"icon":{"paths":["M1020.192 401.824c-8.864-25.568-31.616-44.288-59.008-48.352l-266.432-39.616-115.808-240.448c-12.192-25.248-38.272-41.408-66.944-41.408s-54.752 16.16-66.944 41.408l-115.808 240.448-266.464 39.616c-27.36 4.064-50.112 22.784-58.944 48.352-8.8 25.632-2.144 53.856 17.184 73.12l195.264 194.944-45.28 270.432c-4.608 27.232 7.2 54.56 30.336 70.496 12.704 8.736 27.648 13.184 42.592 13.184 12.288 0 24.608-3.008 35.776-8.992l232.288-125.056 232.32 125.056c11.168 5.984 23.488 8.992 35.744 8.992 14.944 0 29.888-4.448 42.624-13.184 23.136-15.936 34.88-43.264 30.304-70.496l-45.312-270.432 195.328-194.944c19.296-19.296 25.92-47.52 17.184-73.12zM754.816 619.616c-16.384 16.32-23.808 39.328-20.064 61.888l45.312 270.432-232.32-124.992c-11.136-6.016-23.424-8.992-35.776-8.992-12.288 0-24.608 3.008-35.744 8.992l-232.32 124.992 45.312-270.432c3.776-22.56-3.648-45.568-20.032-61.888l-195.264-194.944 266.432-39.68c24.352-3.616 45.312-18.848 55.776-40.576l115.872-240.384 115.84 240.416c10.496 21.728 31.424 36.928 55.744 40.576l266.496 39.68-195.264 194.912z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["star","favorite"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":3,"prevSize":32,"code":59706,"name":"control-Stars"},"setIdx":2,"setId":1,"iconIdx":88},{"icon":{"paths":["M409.6 204.8h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2zM768 204.8h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2zM409.6 563.2h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2zM768 563.2h-153.6c-28.314 0-51.2 22.886-51.2 51.2v153.6c0 28.262 22.886 51.2 51.2 51.2h153.6c28.314 0 51.2-22.938 51.2-51.2v-153.6c0-28.262-22.886-51.2-51.2-51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["grid"],"grid":20},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":20,"code":59730,"name":"grid1"},"setIdx":2,"setId":1,"iconIdx":89},{"icon":{"paths":["M737.28 460.8h-296.96c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h296.96c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM839.68 716.8h-399.36c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h399.36c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM440.32 307.2h399.36c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2h-399.36c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2zM276.48 460.8h-92.16c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h92.16c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM276.48 716.8h-92.16c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h92.16c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2zM276.48 204.8h-92.16c-28.262 0-30.72 22.886-30.72 51.2s2.458 51.2 30.72 51.2h92.16c28.262 0 30.72-22.886 30.72-51.2s-2.458-51.2-30.72-51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["list"],"grid":20},"attrs":[{}],"properties":{"order":1,"id":1,"name":"list","prevSize":20,"code":59726},"setIdx":2,"setId":1,"iconIdx":90},{"icon":{"paths":["M636.518 0c68.608 0 102.912 46.694 102.912 100.198 0 66.816-59.597 128.614-137.165 128.614-64.973 0-102.861-38.4-101.069-101.888 0-53.402 45.107-126.925 135.322-126.925zM425.421 1024c-54.17 0-93.85-33.382-55.962-180.429l62.157-260.71c10.803-41.677 12.595-58.419 0-58.419-16.23 0-86.477 28.774-128.102 57.19l-27.034-45.056c131.686-111.923 283.187-177.51 348.211-177.51 54.118 0 63.13 65.178 36.096 165.376l-71.219 274.022c-12.595 48.384-7.219 65.075 5.427 65.075 16.23 0 69.478-20.070 121.805-61.798l30.72 41.677c-128.102 130.406-268.032 180.582-322.099 180.582z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["info"],"grid":20},"attrs":[{}],"properties":{"order":1,"id":2,"prevSize":20,"code":59708,"name":"info"},"setIdx":2,"setId":1,"iconIdx":91},{"icon":{"paths":["M950.857 932.571v-621.714c0-9.714-8.571-18.286-18.286-18.286h-621.714c-9.714 0-18.286 8.571-18.286 18.286v621.714c0 9.714 8.571 18.286 18.286 18.286h621.714c9.714 0 18.286-8.571 18.286-18.286zM1024 310.857v621.714c0 50.286-41.143 91.429-91.429 91.429h-621.714c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h621.714c50.286 0 91.429 41.143 91.429 91.429zM804.571 91.429v91.429h-73.143v-91.429c0-9.714-8.571-18.286-18.286-18.286h-621.714c-9.714 0-18.286 8.571-18.286 18.286v621.714c0 9.714 8.571 18.286 18.286 18.286h91.429v73.143h-91.429c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h621.714c50.286 0 91.429 41.143 91.429 91.429z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["clone"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":28,"code":59754,"name":"clone"},"setIdx":2,"setId":1,"iconIdx":92},{"icon":{"paths":["M498.787 330.323v-49.548h112.31v-66.065c0-49.548-39.639-89.187-89.187-89.187s-89.187 39.639-89.187 89.187v541.729l89.187 161.858 89.187-161.858v-426.116z","M360.052 716.8h-66.065c-59.458 0-105.703-46.245-105.703-105.703v-254.348c0-59.458 46.245-105.703 105.703-105.703h66.065v-42.942h-66.065c-82.581 0-148.645 66.065-148.645 148.645v254.348c0 82.581 66.065 148.645 148.645 148.645h66.065z","M852.232 260.955c-26.426-33.032-66.065-52.852-109.006-52.852h-59.458v42.942h39.639c42.942 0 82.581 19.819 109.006 52.852l145.342 181.677-142.039 178.374c-26.426 33.032-69.368 52.852-112.31 52.852h-36.335v42.942h56.155c42.942 0 85.884-19.819 112.31-52.852l178.374-221.316z"],"width":1140,"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Tags"],"grid":14},"attrs":[{},{},{}],"properties":{"order":119,"id":1,"name":"control-Tags","prevSize":28,"code":59747},"setIdx":2,"setId":1,"iconIdx":93},{"icon":{"paths":["M384 179.2h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6zM998.4 486.4h-614.4c-14.131 0-25.6 11.443-25.6 25.6s11.469 25.6 25.6 25.6h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6zM998.4 844.8h-614.4c-38.406 15.539-22.811 37.543 0 51.2h614.4c14.157 0 25.6-11.443 25.6-25.6s-11.443-25.6-25.6-25.6z","M0 0v307.2h307.2v-307.2zM47.4 47.4h212.4v212.4h-212.4z","M0 716.8v307.2h307.2v-307.2zM47.4 764.2h212.4v212.4h-212.4z","M0 358.4v307.2h307.2v-307.2zM47.4 405.8h212.4v212.4h-212.4z","M89.6 89.6h128v128h-128v-128z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Checkboxes"],"grid":14},"attrs":[{},{},{},{},{}],"properties":{"order":118,"id":2,"name":"control-Checkboxes","prevSize":28,"code":59746},"setIdx":2,"setId":1,"iconIdx":94},{"icon":{"paths":["M159.073 665.6l-159.073-134.055 159.073-133.819 36.818 37.29-117.062 96.057 117.062 97.237z","M493.247 536.029q0 33.042-9.441 57.115-9.205 24.073-25.961 40.122-16.521 15.813-39.178 23.601-22.657 7.552-49.327 7.552-26.197 0-48.855-4.012-22.421-3.776-42.954-10.385v-323.338h57.587v78.356l-2.36 47.203q12.981-16.757 30.21-26.905 17.465-10.149 41.774-10.149 21.241 0 37.762 8.496t27.614 24.309q11.329 15.577 17.229 37.998 5.9 22.185 5.9 50.035zM432.828 538.389q0-19.825-2.832-33.75t-8.26-22.893q-5.192-8.969-12.981-12.981-7.552-4.248-17.465-4.248-14.633 0-28.086 11.801-13.217 11.801-28.086 32.098v104.79q6.844 2.596 16.757 4.248 10.149 1.652 20.533 1.652 13.689 0 24.781-5.664 11.329-5.664 19.117-16.049 8.024-10.385 12.273-25.253 4.248-15.105 4.248-33.75z","M700.682 513.608q0.472-13.453-1.416-22.893-1.652-9.441-5.664-15.577-3.776-6.136-9.441-8.968t-12.981-2.832q-12.745 0-26.433 10.621-13.453 10.385-29.738 34.458v151.756h-59.003v-239.789h52.159l2.124 34.93q5.9-9.205 13.217-16.521 7.552-7.316 16.521-12.509 9.205-5.428 20.297-8.26t24.309-2.832q18.173 0 32.098 6.372 14.161 6.136 23.601 18.409 9.677 12.273 14.161 30.918 4.72 18.409 4.012 42.718z","M864.927 397.725l159.073 133.819-159.073 134.055-36.582-37.29 116.826-96.293-116.826-97.001z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Html"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":116,"id":3,"name":"control-Html","prevSize":28,"code":59744},"setIdx":2,"setId":1,"iconIdx":95},{"icon":{"paths":["M251.429 100.58c-87.896 0-160 72.104-160 160v525.714c0 87.896 72.104 160 160 160h525.714c87.896 0 160-72.104 160-160v-525.714c0-87.896-72.104-160-160-160zM251.429 146.295h525.714c62.961 0 114.286 51.325 114.286 114.286v525.714c0 62.961-51.325 114.286-114.286 114.286h-525.714c-62.961 0-114.286-51.325-114.286-114.286v-525.714c0-62.961 51.325-114.286 114.286-114.286z","M251.429 306.295c-0.096-0.001-0.21-0.002-0.323-0.002-12.625 0-22.859 10.235-22.859 22.859s10.235 22.859 22.859 22.859c0.114 0 0.227-0.001 0.34-0.002l-0.017 0h525.714c0.096 0.001 0.21 0.002 0.323 0.002 12.625 0 22.859-10.235 22.859-22.859s-10.235-22.859-22.859-22.859c-0.114 0-0.227 0.001-0.34 0.002l0.017-0z","M251.429 443.438c-0.096-0.001-0.21-0.002-0.323-0.002-12.625 0-22.859 10.235-22.859 22.859s10.235 22.859 22.859 22.859c0.114 0 0.227-0.001 0.34-0.002l-0.017 0h297.143c0.096 0.001 0.21 0.002 0.323 0.002 12.625 0 22.859-10.235 22.859-22.859s-10.235-22.859-22.859-22.859c-0.114 0-0.227 0.001-0.34 0.002l0.017-0z","M251.429 580.58c-0.096-0.001-0.21-0.002-0.323-0.002-12.625 0-22.859 10.235-22.859 22.859s10.235 22.859 22.859 22.859c0.114 0 0.227-0.001 0.34-0.002l-0.017 0h297.143c0.096 0.001 0.21 0.002 0.323 0.002 12.625 0 22.859-10.235 22.859-22.859s-10.235-22.859-22.859-22.859c-0.114 0-0.227 0.001-0.34 0.002l0.017-0z"],"width":1029,"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["single-content"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":112,"id":4,"name":"single-content","prevSize":28,"code":59736},"setIdx":2,"setId":1,"iconIdx":96},{"icon":{"paths":["M777.143 946.286h-525.714c-89.143 0-160-70.857-160-160v-297.143c0-89.143 70.857-160 160-160h525.714c89.143 0 160 70.857 160 160v297.143c0 89.143-70.857 160-160 160zM251.429 374.857c-64 0-114.286 50.286-114.286 114.286v297.143c0 64 50.286 114.286 114.286 114.286h525.714c64 0 114.286-50.286 114.286-114.286v-297.143c0-64-50.286-114.286-114.286-114.286h-525.714z","M731.429 580.571h-457.143c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h457.143c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z","M502.857 740.571h-228.571c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h228.571c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z","M777.143 260.571h-525.714c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h525.714c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z","M685.714 146.286h-342.857c-13.714 0-22.857-9.143-22.857-22.857s9.143-22.857 22.857-22.857h342.857c13.714 0 22.857 9.143 22.857 22.857s-9.143 22.857-22.857 22.857z"],"width":1029,"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["multiple-content"],"grid":14},"attrs":[{},{},{},{},{}],"properties":{"order":113,"id":5,"name":"multiple-content","prevSize":28,"code":59735},"setIdx":2,"setId":1,"iconIdx":97},{"icon":{"paths":["M832 268.8h-657.92c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h657.92c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z","M832 453.12h-409.6c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h409.6c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z","M832 642.56h-409.6c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h409.6c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z","M832 832h-409.6c-15.36 0-25.6-10.24-25.6-25.6s10.24-25.6 25.6-25.6h409.6c15.36 0 25.6 10.24 25.6 25.6s-10.24 25.6-25.6 25.6z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["type-Array"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":108,"id":6,"name":"type-Array","prevSize":28,"code":59734},"setIdx":2,"setId":1,"iconIdx":98},{"icon":{"paths":["M292.571 713.143v128c0 20-16.571 36.571-36.571 36.571h-146.286c-20 0-36.571-16.571-36.571-36.571v-128c0-20 16.571-36.571 36.571-36.571h146.286c20 0 36.571 16.571 36.571 36.571zM309.714 109.714l-16 438.857c-0.571 20-17.714 36.571-37.714 36.571h-146.286c-20 0-37.143-16.571-37.714-36.571l-16-438.857c-0.571-20 15.429-36.571 35.429-36.571h182.857c20 0 36 16.571 35.429 36.571z"],"width":366,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["exclamation"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":7,"prevSize":28,"code":59733,"name":"exclamation"},"setIdx":2,"setId":1,"iconIdx":99},{"icon":{"paths":["M512 26.38l-424.96 242.8v485.64l424.96 242.8 424.96-242.8v-485.64l-424.96-242.8zM512 235.52l245.76 138.24v276.48l-245.76 138.24-245.76-138.24v-276.48l245.76-138.24z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["orleans"],"grid":14},"attrs":[{}],"properties":{"order":99,"id":8,"name":"orleans","prevSize":28,"code":59723},"setIdx":2,"setId":1,"iconIdx":100},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v204.8h51.2v-204.8h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-307.2v51.2h307.2c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM716.8 189.8l117.4 117.4h-117.4z","M153.6 640v281.6h358.4v-281.6zM179.2 640v-76.8c0-84.48 69.12-153.6 153.6-153.6s153.6 69.12 153.6 153.6v76.8h-51.2v-76.8c0-56.32-46.080-102.4-102.4-102.4s-102.4 46.080-102.4 102.4v76.8z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-lock"],"grid":14},"attrs":[{},{}],"properties":{"order":97,"id":9,"name":"document-lock","prevSize":28,"code":59721},"setIdx":2,"setId":1,"iconIdx":101},{"icon":{"paths":["M358.4 102.4c-28.314 0-51.2 22.886-51.2 51.2v153.6h51.2v-153.6h307.2v153.6c0 28.314 22.886 51.2 51.2 51.2h153.6v512h-358.4v51.2h358.4c28.314 0 51.2-22.886 51.2-51.2v-548.2l-219.8-219.8h-292.2zM716.8 189.8l117.4 117.4h-117.4zM332.8 460.8l-230.4 256v51.2h102.4v153.6h256v-153.6h102.4v-51.2zM332.8 537.3l161.5 179.5h-84.7v153.6h-153.6v-153.6h-84.7z","M102.4 357.532h460.8v52.068h-460.8v-52.068z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-unpublish"],"grid":14},"attrs":[{},{}],"properties":{"order":96,"id":10,"name":"document-unpublish","prevSize":28,"code":59711},"setIdx":2,"setId":1,"iconIdx":102},{"icon":{"paths":["M614.286 420.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-down"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":11,"prevSize":28,"code":59648,"name":"angle-down"},"setIdx":2,"setId":1,"iconIdx":103},{"icon":{"paths":["M358.286 310.857c0 4.571-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8 5.714 13.143z"],"width":384,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-left"],"grid":14},"attrs":[{}],"properties":{"order":2,"id":12,"prevSize":28,"code":59649,"name":"angle-left"},"setIdx":2,"setId":1,"iconIdx":104},{"icon":{"paths":["M340 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8-5.714-13.143 0-4.571 2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":347,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-right"],"grid":14},"attrs":[{}],"properties":{"order":67,"id":13,"prevSize":28,"code":59697,"name":"angle-right"},"setIdx":2,"setId":1,"iconIdx":105},{"icon":{"paths":["M614.286 676.571c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["angle-up"],"grid":14},"attrs":[{}],"properties":{"order":2,"id":14,"prevSize":28,"code":59651,"name":"angle-up"},"setIdx":2,"setId":1,"iconIdx":106},{"icon":{"paths":["M592 393.6h-156.8c-57.6 0-105.6-48-105.6-105.6v-182.4c0-57.6 48-105.6 105.6-105.6h156.8c57.6 0 105.6 48 105.6 105.6v182.4c-3.2 57.6-48 105.6-105.6 105.6zM432 64c-22.4 0-41.6 19.2-41.6 41.6v182.4c0 22.4 19.2 41.6 41.6 41.6h156.8c22.4 0 41.6-19.2 41.6-41.6v-182.4c0-22.4-19.2-41.6-41.6-41.6h-156.8z","M195.2 1024c-105.6 0-195.2-89.6-195.2-195.2 0-108.8 89.6-195.2 195.2-195.2s195.2 89.6 195.2 195.2c3.2 105.6-86.4 195.2-195.2 195.2zM195.2 694.4c-73.6 0-131.2 60.8-131.2 131.2 0 73.6 60.8 134.4 131.2 134.4 73.6 0 131.2-60.8 131.2-131.2 3.2-73.6-57.6-134.4-131.2-134.4z","M828.8 1024c-108.8 0-195.2-89.6-195.2-195.2 0-108.8 89.6-195.2 195.2-195.2s195.2 89.6 195.2 195.2c0 105.6-89.6 195.2-195.2 195.2zM828.8 694.4c-73.6 0-131.2 60.8-131.2 131.2 0 73.6 60.8 131.2 131.2 131.2 73.6 0 131.2-60.8 131.2-131.2s-60.8-131.2-131.2-131.2z","M332.8 640c-6.4 0-12.8 0-16-3.2-16-9.6-19.2-28.8-9.6-44.8l83.2-137.6c9.6-16 28.8-19.2 44.8-9.6s19.2 28.8 9.6 44.8l-83.2 137.6c-6.4 6.4-16 12.8-28.8 12.8z","M691.2 640c-9.6 0-22.4-6.4-28.8-16l-83.2-137.6c-9.6-16-3.2-35.2 9.6-44.8s35.2-3.2 44.8 9.6l83.2 137.6c9.6 16 3.2 35.2-9.6 44.8-6.4 6.4-12.8 6.4-16 6.4z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["api"],"grid":14},"attrs":[{},{},{},{},{}],"properties":{"order":94,"id":15,"name":"api","prevSize":28,"code":59717},"setIdx":2,"setId":1,"iconIdx":107},{"icon":{"paths":["M800 1024h-576c-124.8 0-224-99.2-224-224v-576c0-124.8 99.2-224 224-224h576c124.8 0 224 99.2 224 224v576c0 124.8-99.2 224-224 224zM224 64c-89.6 0-160 70.4-160 160v576c0 89.6 70.4 160 160 160h576c89.6 0 160-70.4 160-160v-576c0-89.6-70.4-160-160-160h-576z","M771.2 860.8h-438.4c-12.8 0-22.4-6.4-28.8-19.2s-3.2-25.6 3.2-35.2l300.8-355.2c6.4-6.4 16-12.8 25.6-12.8s19.2 6.4 25.6 12.8l192 275.2c3.2 3.2 3.2 6.4 3.2 9.6 16 44.8 3.2 73.6-6.4 89.6-22.4 32-70.4 35.2-76.8 35.2zM403.2 796.8h371.2c6.4 0 22.4-3.2 25.6-9.6 3.2-3.2 3.2-12.8 0-25.6l-166.4-236.8-230.4 272z","M332.8 502.4c-76.8 0-140.8-64-140.8-140.8s64-140.8 140.8-140.8 140.8 64 140.8 140.8-60.8 140.8-140.8 140.8zM332.8 284.8c-41.6 0-76.8 32-76.8 76.8s35.2 76.8 76.8 76.8 76.8-35.2 76.8-76.8-32-76.8-76.8-76.8z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["assets"],"grid":14},"attrs":[{},{},{}],"properties":{"order":95,"id":16,"name":"assets","prevSize":28,"code":59720},"setIdx":2,"setId":1,"iconIdx":108},{"icon":{"paths":["M932.571 548.571c0 20-16.571 36.571-36.571 36.571h-128c0 71.429-15.429 125.143-38.286 165.714l118.857 119.429c14.286 14.286 14.286 37.143 0 51.429-6.857 7.429-16.571 10.857-25.714 10.857s-18.857-3.429-25.714-10.857l-113.143-112.571s-74.857 68.571-172 68.571v-512h-73.143v512c-103.429 0-178.857-75.429-178.857-75.429l-104.571 118.286c-7.429 8-17.143 12-27.429 12-8.571 0-17.143-2.857-24.571-9.143-14.857-13.714-16-36.571-2.857-52l115.429-129.714c-20-39.429-33.143-90.286-33.143-156.571h-128c-20 0-36.571-16.571-36.571-36.571s16.571-36.571 36.571-36.571h128v-168l-98.857-98.857c-14.286-14.286-14.286-37.143 0-51.429s37.143-14.286 51.429 0l98.857 98.857h482.286l98.857-98.857c14.286-14.286 37.143-14.286 51.429 0s14.286 37.143 0 51.429l-98.857 98.857v168h128c20 0 36.571 16.571 36.571 36.571zM658.286 219.429h-365.714c0-101.143 81.714-182.857 182.857-182.857s182.857 81.714 182.857 182.857z"],"width":951,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["bug"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":17,"prevSize":28,"code":59709,"name":"bug"},"setIdx":2,"setId":1,"iconIdx":109},{"icon":{"paths":["M585.143 402.286c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"],"width":585,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-down"],"grid":14},"attrs":[{}],"properties":{"order":4,"id":18,"prevSize":28,"code":59692,"name":"caret-down"},"setIdx":2,"setId":1,"iconIdx":110},{"icon":{"paths":["M365.714 256v512c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":402,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-left"],"grid":14},"attrs":[{}],"properties":{"order":2,"id":19,"prevSize":28,"code":59690,"name":"caret-left"},"setIdx":2,"setId":1,"iconIdx":111},{"icon":{"paths":["M329.143 512c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-512c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":329,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-right"],"grid":14},"attrs":[{}],"properties":{"order":1,"id":20,"prevSize":28,"code":59689,"name":"caret-right"},"setIdx":2,"setId":1,"iconIdx":112},{"icon":{"paths":["M585.143 694.857c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["caret-up"],"grid":14},"attrs":[{}],"properties":{"order":3,"id":21,"prevSize":28,"code":59691,"name":"caret-up"},"setIdx":2,"setId":1,"iconIdx":113},{"icon":{"paths":["M800 1024h-576c-124.8 0-224-99.2-224-224v-576c0-124.8 99.2-224 224-224h576c124.8 0 224 99.2 224 224v576c0 124.8-99.2 224-224 224zM224 64c-89.6 0-160 70.4-160 160v576c0 89.6 70.4 160 160 160h576c89.6 0 160-70.4 160-160v-576c0-89.6-70.4-160-160-160h-576z","M480 448h-211.2c-57.6 0-105.6-48-105.6-105.6v-73.6c0-57.6 48-105.6 105.6-105.6h211.2c57.6 0 105.6 48 105.6 105.6v73.6c0 57.6-48 105.6-105.6 105.6zM268.8 227.2c-22.4 0-41.6 19.2-41.6 41.6v73.6c0 22.4 19.2 41.6 41.6 41.6h211.2c22.4 0 41.6-19.2 41.6-41.6v-73.6c0-22.4-19.2-41.6-41.6-41.6h-211.2z","M828.8 611.2h-633.6c-19.2 0-32-12.8-32-32s12.8-32 32-32h630.4c19.2 0 32 12.8 32 32s-12.8 32-28.8 32z","M553.6 777.6h-358.4c-19.2 0-32-12.8-32-32s12.8-32 32-32h355.2c19.2 0 32 12.8 32 32s-12.8 32-28.8 32z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["content"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":93,"id":22,"name":"contents, trigger-ContentChanged","prevSize":28,"code":59718},"setIdx":2,"setId":1,"iconIdx":114},{"icon":{"paths":["M947.2 102.4h-128v-25.6c0-14.131-11.469-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-512v-25.6c0-14.131-11.52-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-128c-42.342 0-76.8 34.458-76.8 76.8v716.8c0 42.342 34.458 76.8 76.8 76.8h870.4c42.342 0 76.8-34.458 76.8-76.8v-716.8c0-42.342-34.458-76.8-76.8-76.8zM972.8 896c0 14.131-11.469 25.6-25.6 25.6h-870.4c-14.080 0-25.6-11.469-25.6-25.6v-537.6h921.6v537.6zM972.8 307.2h-921.6v-128c0-14.080 11.52-25.6 25.6-25.6h128v76.8c0 14.080 11.52 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h512v76.8c0 14.080 11.469 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h128c14.131 0 25.6 11.52 25.6 25.6v128zM332.8 512h51.2c14.080 0 25.6-11.52 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.52-25.6 25.6s11.52 25.6 25.6 25.6zM640 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 512h51.2c14.131 0 25.6-11.52 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.52-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 614.4h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 614.4h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 716.8h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 716.8h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM179.2 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM332.8 819.2h51.2c14.080 0 25.6-11.469 25.6-25.6s-11.52-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM486.4 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.080 0-25.6 11.469-25.6 25.6s11.52 25.6 25.6 25.6zM640 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6zM793.6 819.2h51.2c14.131 0 25.6-11.469 25.6-25.6s-11.469-25.6-25.6-25.6h-51.2c-14.131 0-25.6 11.469-25.6 25.6s11.469 25.6 25.6 25.6z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-date"],"grid":14},"attrs":[{}],"properties":{"order":71,"id":23,"name":"control-Date","prevSize":28,"code":59702},"setIdx":2,"setId":1,"iconIdx":115},{"icon":{"paths":["M486.4 409.6h51.2c14.080 0 25.6 11.52 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.52-25.6-25.6s11.52-25.6 25.6-25.6zM230.4 614.4c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM230.4 512c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM51.2 742.4v-435.2h665.6v102.4h51.2v-281.6c0-42.342-34.458-76.8-76.8-76.8h-128v-25.6c0-14.131-11.469-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-256v-25.6c0-14.131-11.52-25.6-25.6-25.6s-25.6 11.469-25.6 25.6v25.6h-128c-42.342 0-76.8 34.458-76.8 76.8v614.4c0 42.342 34.458 76.8 76.8 76.8h332.8v-51.2h-332.8c-14.080 0-25.6-11.469-25.6-25.6zM51.2 128c0-14.080 11.52-25.6 25.6-25.6h128v76.8c0 14.080 11.52 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h256v76.8c0 14.080 11.469 25.6 25.6 25.6s25.6-11.52 25.6-25.6v-76.8h128c14.131 0 25.6 11.52 25.6 25.6v128h-665.6v-128zM384 409.6c14.080 0 25.6 11.52 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.52-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM742.4 460.8c-155.546 0-281.6 126.054-281.6 281.6s126.054 281.6 281.6 281.6 281.6-126.054 281.6-281.6-126.054-281.6-281.6-281.6zM742.4 972.8c-127.232 0-230.4-103.168-230.4-230.4s103.168-230.4 230.4-230.4 230.4 103.168 230.4 230.4-103.168 230.4-230.4 230.4zM384 512c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM384 614.4c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6h51.2zM844.8 716.8c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-102.4c-14.131 0-25.6-11.469-25.6-25.6v-102.4c0-14.131 11.469-25.6 25.6-25.6s25.6 11.469 25.6 25.6v76.8h76.8z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-date-time"],"grid":14},"attrs":[{}],"properties":{"order":70,"id":24,"name":"control-DateTime","prevSize":28,"code":59703},"setIdx":2,"setId":1,"iconIdx":116},{"icon":{"paths":["M793.6 609.416h-61.838v-28.108h-0.783q-21.135 33.092-62.034 33.092-37.573 0-60.469-26.912-22.896-27.112-22.896-75.554 0-50.635 25.244-81.136t66.144-30.501q38.747 0 54.011 28.308h0.783v-121.405h61.838v302.216zM732.936 510.139v-15.35q0-19.935-11.35-33.092t-29.549-13.157q-20.548 0-32.093 16.546-11.546 16.347-11.546 45.053 0 26.912 11.154 41.465t30.919 14.553q18.786 0 30.528-15.35 11.937-15.35 11.937-40.668zM548.594 609.416h-61.643v-116.421q0-44.455-32.093-44.455-15.264 0-24.853 13.357t-9.589 33.292v114.228h-61.839v-117.617q0-43.259-31.506-43.259-15.851 0-25.44 12.758-9.393 12.758-9.393 34.687v113.431h-61.838v-204.135h61.838v31.896h0.783q9.589-16.347 26.81-26.514 17.417-10.366 37.964-10.366 42.465 0 58.12 38.076 22.896-38.076 67.318-38.076 65.361 0 65.361 82.133v126.987zM0 0v204.8h76.8v76.8h51.2v-76.8h76.8v-204.8zM819.2 0v204.8h204.8v-204.8zM51.2 51.2h102.4v102.4h-102.4zM870.4 51.2h102.4v102.4h-102.4zM281.6 76.8v51.2h102.4v-51.2zM486.4 76.8v51.2h102.4v-51.2zM691.2 76.8v51.2h102.4v-51.2zM896 281.6v102.4h51.2v-102.4zM76.8 384v102.4h51.2v-102.4zM896 486.4v102.4h51.2v-102.4zM76.8 588.8v102.4h51.2v-102.4zM896 691.2v102.4h51.2v-102.4zM76.8 793.6v25.6h-76.8v204.8h204.8v-76.8h76.8v-51.2h-76.8v-76.8h-76.8v-25.6zM819.2 819.2v76.8h-25.6v51.2h25.6v76.8h204.8v-204.8zM51.2 870.4h102.4v102.4h-102.4zM870.4 870.4h102.4v102.4h-102.4zM384 896v51.2h102.4v-51.2zM588.8 896v51.2h102.4v-51.2z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["control-Markdown"],"grid":14},"attrs":[{}],"properties":{"order":72,"id":25,"name":"control-Markdown","prevSize":28,"code":59704},"setIdx":2,"setId":1,"iconIdx":117},{"icon":{"paths":["M292.571 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["th"],"defaultCode":61450,"grid":14},"attrs":[],"properties":{"name":"grid","id":26,"order":83,"prevSize":28,"code":61450},"setIdx":2,"setId":1,"iconIdx":118},{"icon":{"paths":["M877.714 768v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 475.429v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 182.857v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["bars","navicon","reorder"],"defaultCode":61641,"grid":14},"attrs":[],"properties":{"name":"list1","id":27,"order":89,"prevSize":28,"code":61641},"setIdx":2,"setId":1,"iconIdx":119},{"icon":{"paths":["M512 64c-131.696 0-239.125 107.4-239.125 239 0 65.8 24.831 146.717 65.375 215.25 19.653 33.221 43.902 63.853 71.75 87.125-59.423 7.524-122.009 9.415-172.125 32-79.809 35.967-144.343 94.74-172.375 178.625-1.5 9.499 0 0-1.5 9v0.499c0 73.995 60.563 134.501 134.375 134.501h627.125c73.888 0 134.5-60.506 134.5-134.5l-1.5-9.375c-27.845-84.263-92.273-143.119-172.125-179-50.17-22.544-112.844-24.421-172.375-31.875 27.792-23.26 52.002-53.831 71.625-87 40.544-68.533 65.375-149.45 65.375-215.25 0-131.6-107.304-239-239-239zM512 124c99.241 0 179 79.875 179 179 0 49.562-21.877 125.381-57 184.75s-81.435 98.75-122 98.75c-40.565 0-86.877-39.381-122-98.75s-57.125-135.188-57.125-184.75c0-99.125 79.884-179 179.125-179zM512 646.5c92.551 0 180.829 14.406 249.75 45.375 66.784 30.009 113.649 74.724 136.5 137.75-2.447 39.259-32.9 70.375-72.75 70.375h-627.125c-39.678 0-70.116-31.051-72.625-70.25 22.978-62.705 69.953-107.523 136.75-137.625 68.937-31.067 157.205-45.625 249.5-45.625z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["user-o"],"grid":14},"attrs":[{}],"properties":{"order":64,"id":28,"name":"user-o","prevSize":28,"code":59698},"setIdx":2,"setId":1,"iconIdx":120},{"icon":{"paths":["M217.6 992c-3.2 0-3.2 0-6.4 0h-3.2c-144-25.6-208-144-208-249.6 0-99.2 57.6-208 185.6-240v-147.2c0-19.2 12.8-32 32-32s32 12.8 32 32v172.8c0 16-12.8 28.8-25.6 32-108.8 16-160 102.4-160 182.4s48 166.4 153.6 185.6h6.4c16 3.2 28.8 19.2 25.6 38.4-3.2 16-16 25.6-32 25.6z","M774.4 1001.6c0 0 0 0 0 0-102.4 0-211.2-60.8-243.2-185.6h-176c-19.2 0-32-12.8-32-32s12.8-32 32-32h201.6c16 0 28.8 12.8 32 25.6 16 108.8 102.4 156.8 182.4 160 80 0 166.4-48 185.6-153.6v-3.2c3.2-16 19.2-28.8 38.4-25.6 16 3.2 28.8 19.2 25.6 38.4v3.2c-22.4 140.8-140.8 204.8-246.4 204.8z","M787.2 678.4c-19.2 0-32-12.8-32-32v-176c0-16 12.8-28.8 25.6-32 108.8-16 156.8-102.4 160-182.4 0-80-48-166.4-153.6-185.6h-3.2c-19.2-6.4-32-22.4-28.8-38.4s19.2-28.8 38.4-25.6h3.2c144 25.6 208 144 208 249.6 0 99.2-60.8 208-185.6 240v150.4c0 16-16 32-32 32z","M41.6 246.4c-3.2 0-3.2 0-6.4 0-16-3.2-28.8-19.2-25.6-35.2v-3.2c25.6-144 140.8-208 246.4-208 0 0 3.2 0 3.2 0 99.2 0 208 60.8 240 185.6h147.2c19.2 0 32 12.8 32 32s-12.8 32-32 32h-172.8c-16 0-28.8-12.8-32-25.6-16-108.8-102.4-156.8-182.4-160-80 0-166.4 48-185.6 153.6v3.2c-3.2 16-16 25.6-32 25.6z","M256 387.2c-32 0-67.2-12.8-92.8-38.4-51.2-51.2-51.2-134.4 0-185.6 25.6-22.4 57.6-35.2 92.8-35.2s67.2 12.8 92.8 38.4c25.6 25.6 38.4 57.6 38.4 92.8s-12.8 67.2-38.4 92.8c-25.6 22.4-57.6 35.2-92.8 35.2zM256 192c-16 0-32 6.4-44.8 19.2-25.6 25.6-25.6 67.2 0 92.8s67.2 25.6 92.8 0c12.8-12.8 19.2-28.8 19.2-48s-6.4-32-19.2-44.8-28.8-19.2-48-19.2z","M771.2 873.6c-32 0-67.2-12.8-92.8-38.4-51.2-51.2-51.2-134.4 0-185.6 25.6-25.6 57.6-38.4 92.8-38.4s67.2 12.8 92.8 38.4c25.6 25.6 38.4 57.6 38.4 92.8s-12.8 67.2-38.4 92.8c-28.8 25.6-60.8 38.4-92.8 38.4zM771.2 678.4c-19.2 0-35.2 6.4-48 19.2-25.6 25.6-25.6 67.2 0 92.8s67.2 25.6 92.8 0c12.8-12.8 19.2-28.8 19.2-48s-6.4-35.2-19.2-48-28.8-16-44.8-16z","M745.6 387.2c-32 0-67.2-12.8-92.8-38.4s-38.4-57.6-38.4-92.8 12.8-67.2 38.4-92.8c25.6-22.4 60.8-35.2 92.8-35.2s67.2 12.8 92.8 38.4c51.2 51.2 51.2 134.4 0 185.6v0c-25.6 22.4-57.6 35.2-92.8 35.2zM745.6 192c-19.2 0-35.2 6.4-48 19.2s-19.2 28.8-19.2 48 6.4 35.2 19.2 48c25.6 25.6 67.2 25.6 92.8 0s25.6-67.2 0-92.8c-9.6-16-25.6-22.4-44.8-22.4z","M259.2 873.6c-32 0-67.2-12.8-92.8-38.4s-38.4-57.6-38.4-92.8 12.8-67.2 38.4-92.8c25.6-22.4 57.6-35.2 92.8-35.2s67.2 12.8 92.8 38.4c51.2 51.2 51.2 134.4 0 185.6v0c-25.6 22.4-57.6 35.2-92.8 35.2zM259.2 678.4c-19.2 0-35.2 6.4-48 19.2s-19.2 28.8-19.2 48 6.4 35.2 19.2 48c25.6 25.6 67.2 25.6 92.8 0s25.6-67.2 0-92.8c-9.6-16-25.6-22.4-44.8-22.4z"],"attrs":[{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["webhooks"],"grid":14},"attrs":[{},{},{},{},{},{},{},{}],"properties":{"order":92,"id":29,"name":"rules","prevSize":28,"code":59719},"setIdx":2,"setId":1,"iconIdx":121}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showCodes":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon"},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"name":"icomoon","classSelector":".icon"},"historySize":50}} \ No newline at end of file diff --git a/src/Squidex/app/theme/icomoon/style.css b/src/Squidex/app/theme/icomoon/style.css index 087e4493c..4d7f94963 100644 --- a/src/Squidex/app/theme/icomoon/style.css +++ b/src/Squidex/app/theme/icomoon/style.css @@ -1,10 +1,10 @@ @font-face { font-family: 'icomoon'; - src: url('fonts/icomoon.eot?h3wogz'); - src: url('fonts/icomoon.eot?h3wogz#iefix') format('embedded-opentype'), - url('fonts/icomoon.ttf?h3wogz') format('truetype'), - url('fonts/icomoon.woff?h3wogz') format('woff'), - url('fonts/icomoon.svg?h3wogz#icomoon') format('svg'); + src: url('fonts/icomoon.eot?vuepjz'); + src: url('fonts/icomoon.eot?vuepjz#iefix') format('embedded-opentype'), + url('fonts/icomoon.ttf?vuepjz') format('truetype'), + url('fonts/icomoon.woff?vuepjz') format('woff'), + url('fonts/icomoon.svg?vuepjz#icomoon') format('svg'); font-weight: normal; font-style: normal; } @@ -24,6 +24,48 @@ -moz-osx-font-smoothing: grayscale; } +.icon-corner-down-right:before { + content: "\e977"; +} +.icon-info-outline:before { + content: "\e974"; +} +.icon-upload-2:before { + content: "\e972"; +} +.icon-translate:before { + content: "\e96f"; +} +.icon-arrow_back:before { + content: "\e96e"; +} +.icon-external-link:before { + content: "\e96d"; +} +.icon-minus-square:before { + content: "\e969"; +} +.icon-plus-square:before { + content: "\e968"; +} +.icon-drag2:before { + content: "\e961"; +} +.icon-comments:before { + content: "\e95f"; +} +.icon-backup:before { + content: "\e95b"; +} +.icon-support:before { + content: "\e95a"; +} +.icon-control-RichText:before { + content: "\e939"; +} +.icon-download:before { + content: "\e93e"; +} .icon-type-UI:before { content: "\e975"; } @@ -189,45 +231,6 @@ .icon-upload-4:before { content: "\e971"; } -.icon-info-outline:before { - content: "\e974"; -} -.icon-upload-2:before { - content: "\e972"; -} -.icon-translate:before { - content: "\e96f"; -} -.icon-arrow_back:before { - content: "\e96e"; -} -.icon-external-link:before { - content: "\e96d"; -} -.icon-minus-square:before { - content: "\e969"; -} -.icon-plus-square:before { - content: "\e968"; -} -.icon-drag2:before { - content: "\e961"; -} -.icon-comments:before { - content: "\e95f"; -} -.icon-backup:before { - content: "\e95b"; -} -.icon-support:before { - content: "\e95a"; -} -.icon-control-RichText:before { - content: "\e939"; -} -.icon-download:before { - content: "\e93e"; -} .icon-arrow-right:before { content: "\e976"; } diff --git a/tests/RunCoverage.ps1 b/tests/RunCoverage.ps1 index 01a95a5e0..77bce8d8a 100644 --- a/tests/RunCoverage.ps1 +++ b/tests/RunCoverage.ps1 @@ -76,6 +76,6 @@ if ($all -Or $web) { -oldStyle } -&"$folderHome\.nuget\packages\ReportGenerator\4.0.13.1\tools\net47\ReportGenerator.exe" ` +&"$folderHome\.nuget\packages\ReportGenerator\4.1.6\tools\net47\ReportGenerator.exe" ` -reports:"$folderWorking\$folderReports\*.xml" ` -targetdir:"$folderWorking\$folderReports\Output" \ No newline at end of file diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs index 8cdac0bc8..1f7f48ade 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.ComponentModel; using Squidex.Domain.Apps.Core.Contents; using Xunit; @@ -12,6 +13,24 @@ namespace Squidex.Domain.Apps.Core.Model.Contents { public class StatusTests { + private readonly TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(Status)); + + [Fact] + public void Should_convert_from_string() + { + var result = typeConverter.ConvertFromString("Draft"); + + Assert.Equal(Status.Draft, result); + } + + [Fact] + public void Should_convert_to_string() + { + var result = typeConverter.ConvertToString(Status.Draft); + + Assert.Equal("Draft", result); + } + [Fact] public void Should_initialize_default() { diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowJsonTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowJsonTests.cs new file mode 100644 index 000000000..6719981ec --- /dev/null +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowJsonTests.cs @@ -0,0 +1,26 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using FluentAssertions; +using Squidex.Domain.Apps.Core.Contents; +using Xunit; + +namespace Squidex.Domain.Apps.Core.Model.Contents +{ + public class WorkflowJsonTests + { + [Fact] + public void Should_serialize_and_deserialize() + { + var workflow = Workflow.Default; + + var serialized = workflow.SerializeAndDeserialize(); + + serialized.Should().BeEquivalentTo(workflow); + } + } +} diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowTests.cs new file mode 100644 index 000000000..21515232d --- /dev/null +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowTests.cs @@ -0,0 +1,120 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.Linq; +using Squidex.Domain.Apps.Core.Contents; +using Xunit; + +namespace Squidex.Domain.Apps.Core.Model.Contents +{ + public class WorkflowTests + { + private readonly Workflow workflow = new Workflow( + new Dictionary + { + [Status.Draft] = + new WorkflowStep( + new Dictionary + { + [Status.Archived] = new WorkflowTransition("ToArchivedExpr", "ToArchivedRole"), + [Status.Published] = new WorkflowTransition("ToPublishedExpr", "ToPublishedRole") + }, + StatusColors.Draft), + [Status.Archived] = + new WorkflowStep(), + [Status.Published] = + new WorkflowStep() + }, Status.Draft); + + [Fact] + public void Should_provide_default_workflow_if_none_found() + { + var result = Workflows.Empty.GetFirst(); + + Assert.Same(Workflow.Default, result); + } + + [Fact] + public void Should_provide_initial_state() + { + var (status, step) = workflow.GetInitialStep(); + + Assert.Equal(Status.Draft, status); + Assert.Equal(StatusColors.Draft, step.Color); + Assert.Same(workflow.Steps[Status.Draft], step); + } + + [Fact] + public void Should_provide_step() + { + var found = workflow.TryGetStep(Status.Draft, out var step); + + Assert.True(found); + Assert.Same(workflow.Steps[Status.Draft], step); + } + + [Fact] + public void Should_not_provide_unknown_step() + { + var found = workflow.TryGetStep(default, out var step); + + Assert.False(found); + Assert.Null(step); + } + + [Fact] + public void Should_provide_transition() + { + var found = workflow.TryGetTransition(Status.Draft, Status.Archived, out var transition); + + Assert.True(found); + Assert.Equal("ToArchivedExpr", transition.Expression); + Assert.Equal("ToArchivedRole", transition.Role); + } + + [Fact] + public void Should_not_provide_transition_from_unknown_step() + { + var found = workflow.TryGetTransition(default, Status.Archived, out var transition); + + Assert.False(found); + Assert.Null(transition); + } + + [Fact] + public void Should_not_provide_transition_to_unknown_step() + { + var found = workflow.TryGetTransition(Status.Draft, default, out var transition); + + Assert.False(found); + Assert.Null(transition); + } + + [Fact] + public void Should_provide_transitions() + { + var transitions = workflow.GetTransitions(Status.Draft).ToArray(); + + Assert.Equal(2, transitions.Length); + + var (status1, step1, transition1) = transitions[0]; + + Assert.Equal(Status.Archived, status1); + Assert.Equal("ToArchivedExpr", transition1.Expression); + Assert.Equal("ToArchivedRole", transition1.Role); + Assert.Same(workflow.Steps[Status.Archived], step1); + + var (status2, step2, transition2) = transitions[1]; + + Assert.Equal(Status.Published, status2); + Assert.Equal("ToPublishedExpr", transition2.Expression); + Assert.Equal("ToPublishedRole", transition2.Role); + Assert.Same(workflow.Steps[Status.Published], step2); + } + } +} diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsJsonTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsJsonTests.cs new file mode 100644 index 000000000..52074fee1 --- /dev/null +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsJsonTests.cs @@ -0,0 +1,26 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using FluentAssertions; +using Squidex.Domain.Apps.Core.Contents; +using Xunit; + +namespace Squidex.Domain.Apps.Core.Model.Contents +{ + public class WorkflowsJsonTests + { + [Fact] + public void Should_serialize_and_deserialize() + { + var workflow = Workflows.Empty.Set(Workflow.Default); + + var serialized = workflow.SerializeAndDeserialize(); + + serialized.Should().BeEquivalentTo(workflow); + } + } +} diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsTests.cs new file mode 100644 index 000000000..37ce537c4 --- /dev/null +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/WorkflowsTests.cs @@ -0,0 +1,37 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using Squidex.Domain.Apps.Core.Contents; +using Xunit; + +#pragma warning disable SA1310 // Field names must not contain underscore + +namespace Squidex.Domain.Apps.Core.Model.Contents +{ + public class WorkflowsTests + { + private readonly Workflows workflows_0 = Workflows.Empty; + + [Fact] + public void Should_provide_default_workflow_if_none_found() + { + var workflow = workflows_0.GetFirst(); + + Assert.Same(Workflow.Default, workflow); + } + + [Fact] + public void Should_set_workflow_with_empty_guid() + { + var workflows_1 = workflows_0.Set(Workflow.Default); + + Assert.Single(workflows_1); + Assert.Same(Workflow.Default, workflows_1[Guid.Empty]); + } + } +} diff --git a/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs b/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs index 58692226c..e6e9b36d5 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/TestUtils.cs @@ -58,7 +58,8 @@ namespace Squidex.Domain.Apps.Core new RuleConverter(), new SchemaConverter(), new StatusConverter(), - new StringEnumConverter()), + new StringEnumConverter(), + new WorkflowConverter()), TypeNameHandling = typeNameHandling }; diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs index b5d79dee6..ac892f78a 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Apps; +using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Services; using Squidex.Domain.Apps.Entities.Apps.Services.Implementations; @@ -80,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task Create_should_create_events_and_update_state() { - var command = new CreateApp { Name = AppName, Actor = User, AppId = AppId }; + var command = new CreateApp { Name = AppName, Actor = Actor, AppId = AppId }; var result = await sut.ExecuteAsync(CreateCommand(command)); @@ -91,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Apps LastEvents .ShouldHaveSameEvents( CreateEvent(new AppCreated { Name = AppName }), - CreateEvent(new AppContributorAssigned { ContributorId = User.Identifier, Role = Role.Owner }), + CreateEvent(new AppContributorAssigned { ContributorId = Actor.Identifier, Role = Role.Owner }), CreateEvent(new AppLanguageAdded { Language = Language.EN }), CreateEvent(new AppPatternAdded { PatternId = patternId1, Name = "Number", Pattern = "[0-9]" }), CreateEvent(new AppPatternAdded { PatternId = patternId2, Name = "Numbers", Pattern = "[0-9]*" }) @@ -103,7 +104,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { var command = new ChangePlan { PlanId = planIdPaid }; - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppNamedId, planIdPaid)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid)) .Returns(new PlanChangedResult()); await ExecuteCreateAsync(); @@ -125,10 +126,10 @@ namespace Squidex.Domain.Apps.Entities.Apps { var command = new ChangePlan { PlanId = planIdFree }; - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppNamedId, planIdPaid)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid)) .Returns(new PlanChangedResult()); - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppNamedId, planIdFree)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdFree)) .Returns(new PlanResetResult()); await ExecuteCreateAsync(); @@ -151,7 +152,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { var command = new ChangePlan { PlanId = planIdPaid }; - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppNamedId, planIdPaid)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid)) .Returns(new RedirectToCheckoutResult(new Uri("http://squidex.io"))); await ExecuteCreateAsync(); @@ -174,7 +175,7 @@ namespace Squidex.Domain.Apps.Entities.Apps result.ShouldBeEquivalent(new EntitySavedResult(5)); - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppNamedId, planIdPaid)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid)) .MustNotHaveHappened(); } @@ -256,6 +257,27 @@ namespace Squidex.Domain.Apps.Entities.Apps ); } + [Fact] + public async Task UpdateClient_should_create_events_and_update_state() + { + var command = new UpdateClient { Id = clientId, Name = clientNewName, Role = Role.Developer }; + + await ExecuteCreateAsync(); + await ExecuteAttachClientAsync(); + + var result = await sut.ExecuteAsync(CreateCommand(command)); + + result.ShouldBeEquivalent(sut.Snapshot); + + Assert.Equal(clientNewName, sut.Snapshot.Clients[clientId].Name); + + LastEvents + .ShouldHaveSameEvents( + CreateEvent(new AppClientRenamed { Id = clientId, Name = clientNewName }), + CreateEvent(new AppClientUpdated { Id = clientId, Role = Role.Developer }) + ); + } + [Fact] public async Task RevokeClient_should_create_events_and_update_state() { @@ -277,23 +299,21 @@ namespace Squidex.Domain.Apps.Entities.Apps } [Fact] - public async Task UpdateClient_should_create_events_and_update_state() + public async Task ConfigureWorkflow_should_create_events_and_update_state() { - var command = new UpdateClient { Id = clientId, Name = clientNewName, Role = Role.Developer }; + var command = new ConfigureWorkflow { Workflow = Workflow.Default }; await ExecuteCreateAsync(); - await ExecuteAttachClientAsync(); var result = await sut.ExecuteAsync(CreateCommand(command)); result.ShouldBeEquivalent(sut.Snapshot); - Assert.Equal(clientNewName, sut.Snapshot.Clients[clientId].Name); + Assert.NotEmpty(sut.Snapshot.Workflows); LastEvents .ShouldHaveSameEvents( - CreateEvent(new AppClientRenamed { Id = clientId, Name = clientNewName }), - CreateEvent(new AppClientUpdated { Id = clientId, Role = Role.Developer }) + CreateEvent(new AppWorkflowConfigured { Workflow = Workflow.Default }) ); } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppWorkflowTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppWorkflowTests.cs new file mode 100644 index 000000000..99f2f32ca --- /dev/null +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppWorkflowTests.cs @@ -0,0 +1,152 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Entities.Apps.Commands; +using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; +using Xunit; + +namespace Squidex.Domain.Apps.Entities.Apps.Guards +{ + public class GuardAppWorkflowTests + { + [Fact] + public void CanConfigure_should_throw_exception_if_workflow_is_not_defined() + { + var command = new ConfigureWorkflow(); + + ValidationAssert.Throws(() => GuardAppWorkflows.CanConfigure(command), + new ValidationError("Workflow is required.", "Workflow")); + } + + [Fact] + public void CanConfigure_should_throw_exception_if_workflow_has_no_initial_step() + { + var command = new ConfigureWorkflow + { + Workflow = new Workflow( + new Dictionary + { + [Status.Published] = new WorkflowStep() + }, + default) + }; + + ValidationAssert.Throws(() => GuardAppWorkflows.CanConfigure(command), + new ValidationError("Initial step is required.", "Workflow.Initial")); + } + + [Fact] + public void CanConfigure_should_throw_exception_if_initial_step_is_published() + { + var command = new ConfigureWorkflow + { + Workflow = new Workflow( + new Dictionary + { + [Status.Published] = new WorkflowStep() + }, + Status.Published) + }; + + ValidationAssert.Throws(() => GuardAppWorkflows.CanConfigure(command), + new ValidationError("Initial step cannot be published step.", "Workflow.Initial")); + } + + [Fact] + public void CanConfigure_should_throw_exception_if_workflow_does_not_have_published_state() + { + var command = new ConfigureWorkflow + { + Workflow = new Workflow( + new Dictionary + { + [Status.Draft] = new WorkflowStep() + }, + Status.Draft) + }; + + ValidationAssert.Throws(() => GuardAppWorkflows.CanConfigure(command), + new ValidationError("Workflow must have a published step.", "Workflow.Steps")); + } + + [Fact] + public void CanConfigure_should_throw_exception_if_workflow_step_is_not_defined() + { + var command = new ConfigureWorkflow + { + Workflow = new Workflow( + new Dictionary + { + [Status.Published] = null, + [Status.Draft] = new WorkflowStep() + }, + Status.Draft) + }; + + ValidationAssert.Throws(() => GuardAppWorkflows.CanConfigure(command), + new ValidationError("Step is required.", "Workflow.Steps.Published")); + } + + [Fact] + public void CanConfigure_should_throw_exception_if_workflow_transition_is_invalid() + { + var command = new ConfigureWorkflow + { + Workflow = new Workflow( + new Dictionary + { + [Status.Published] = + new WorkflowStep( + new Dictionary + { + [Status.Archived] = new WorkflowTransition() + }), + [Status.Draft] = new WorkflowStep() + }, + Status.Draft) + }; + + ValidationAssert.Throws(() => GuardAppWorkflows.CanConfigure(command), + new ValidationError("Transition has an invalid target.", "Workflow.Steps.Published.Transitions.Archived")); + } + + [Fact] + public void CanConfigure_should_throw_exception_if_workflow_transition_is_not_defined() + { + var command = new ConfigureWorkflow + { + Workflow = new Workflow( + new Dictionary + { + [Status.Draft] = + new WorkflowStep(), + [Status.Published] = + new WorkflowStep( + new Dictionary + { + [Status.Draft] = null + }) + }, + Status.Draft) + }; + + ValidationAssert.Throws(() => GuardAppWorkflows.CanConfigure(command), + new ValidationError("Transition is required.", "Workflow.Steps.Published.Transitions.Draft")); + } + + [Fact] + public void CanConfigure_should_not_throw_exception_if_workflow_is_valid() + { + var command = new ConfigureWorkflow { Workflow = Workflow.Default }; + + GuardAppWorkflows.CanConfigure(command); + } + } +} diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs index 32a17a952..43070abf8 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Invitation/InviteUserCommandMiddlewareTests.cs @@ -34,13 +34,13 @@ namespace Squidex.Domain.Apps.Entities.Apps.Invitation A.CallTo(() => userResolver.CreateUserIfNotExists("me@email.com", true)) .Returns(true); - var result = A.Fake(); + var app = A.Fake(); - context.Complete(result); + context.Complete(app); await sut.HandleAsync(context); - Assert.Same(context.Result().App, result); + Assert.Same(context.Result().App, app); A.CallTo(() => userResolver.CreateUserIfNotExists("me@email.com", true)) .MustHaveHappened(); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs index 1f2a4fc00..be9ad655e 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs @@ -30,7 +30,7 @@ namespace Squidex.Domain.Apps.Entities.Assets private readonly IAssetRepository assetRepository = A.Fake(); private readonly IAppEntity app = A.Fake(); private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly QueryContext context; + private readonly Context context; private readonly AssetQueryService sut; public AssetQueryServiceTests() @@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Assets A.CallTo(() => app.Name).Returns(appId.Name); A.CallTo(() => app.LanguagesConfig).Returns(LanguagesConfig.English); - context = QueryContext.Create(app, user); + context = new Context(user, app); var options = Options.Create(new AssetOptions { DefaultPageSize = 30 }); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs index 91ed5025a..21d46e431 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs @@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Contents await sut.HandleAsync(context); - A.CallTo(() => contentEnricher.EnrichAsync(A.Ignored)) + A.CallTo(() => contentEnricher.EnrichAsync(A.Ignored, User)) .MustNotHaveHappened(); } @@ -64,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents Assert.Same(result, context.Result()); - A.CallTo(() => contentEnricher.EnrichAsync(A.Ignored)) + A.CallTo(() => contentEnricher.EnrichAsync(A.Ignored, User)) .MustNotHaveHappened(); } @@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Contents var enriched = new ContentEntity(); - A.CallTo(() => contentEnricher.EnrichAsync(result)) + A.CallTo(() => contentEnricher.EnrichAsync(result, User)) .Returns(enriched); await sut.HandleAsync(context); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEnricherTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEnricherTests.cs index f7ba94467..83f406dd9 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEnricherTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEnricherTests.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Contents; @@ -16,13 +17,19 @@ namespace Squidex.Domain.Apps.Entities.Contents { public class ContentEnricherTests { - private readonly IContentWorkflow workflow = A.Fake(); + private readonly IContentWorkflow contentWorkflow = A.Fake(); + private readonly IContextProvider contextProvider = A.Fake(); + private readonly ClaimsPrincipal user = new ClaimsPrincipal(); + private readonly Context context = new Context(); private readonly NamedId schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); private readonly ContentEnricher sut; public ContentEnricherTests() { - sut = new ContentEnricher(workflow); + A.CallTo(() => contextProvider.Context) + .Returns(context); + + sut = new ContentEnricher(contentWorkflow, contextProvider); } [Fact] @@ -30,10 +37,10 @@ namespace Squidex.Domain.Apps.Entities.Contents { var source = new ContentEntity { Status = Status.Published, SchemaId = schemaId }; - A.CallTo(() => workflow.GetInfoAsync(Status.Published)) + A.CallTo(() => contentWorkflow.GetInfoAsync(source)) .Returns(new StatusInfo(Status.Published, StatusColors.Published)); - var result = await sut.EnrichAsync(source); + var result = await sut.EnrichAsync(source, user); Assert.Equal(StatusColors.Published, result.StatusColor); } @@ -43,10 +50,10 @@ namespace Squidex.Domain.Apps.Entities.Contents { var source = new ContentEntity { Status = Status.Published, SchemaId = schemaId }; - A.CallTo(() => workflow.GetInfoAsync(Status.Published)) + A.CallTo(() => contentWorkflow.GetInfoAsync(source)) .Returns(Task.FromResult(null)); - var result = await sut.EnrichAsync(source); + var result = await sut.EnrichAsync(source, user); Assert.Equal(StatusColors.Draft, result.StatusColor); } @@ -54,31 +61,48 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_enrich_content_with_can_update() { + context.WithResolveFlow(true); + var source = new ContentEntity { SchemaId = schemaId }; - A.CallTo(() => workflow.CanUpdateAsync(source)) + A.CallTo(() => contentWorkflow.CanUpdateAsync(source)) .Returns(true); - var result = await sut.EnrichAsync(source); + var result = await sut.EnrichAsync(source, user); Assert.True(result.CanUpdate); } + [Fact] + public async Task Should_not_enrich_content_with_can_update_if_disabled_in_context() + { + context.WithResolveFlow(false); + + var source = new ContentEntity { SchemaId = schemaId }; + + var result = await sut.EnrichAsync(source, user); + + Assert.False(result.CanUpdate); + + A.CallTo(() => contentWorkflow.CanUpdateAsync(source)) + .MustNotHaveHappened(); + } + [Fact] public async Task Should_enrich_multiple_contents_and_cache_color() { var source1 = new ContentEntity { Status = Status.Published, SchemaId = schemaId }; var source2 = new ContentEntity { Status = Status.Published, SchemaId = schemaId }; - A.CallTo(() => workflow.GetInfoAsync(Status.Published)) + A.CallTo(() => contentWorkflow.GetInfoAsync(source1)) .Returns(new StatusInfo(Status.Published, StatusColors.Published)); - var result = await sut.EnrichAsync(new[] { source1, source2 }); + var result = await sut.EnrichAsync(new[] { source1, source2 }, user); Assert.Equal(StatusColors.Published, result[0].StatusColor); Assert.Equal(StatusColors.Published, result[1].StatusColor); - A.CallTo(() => workflow.GetInfoAsync(Status.Published)) + A.CallTo(() => contentWorkflow.GetInfoAsync(A.Ignored)) .MustHaveHappenedOnceExactly(); } } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs index 056301040..197f88146 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly IContentRepository contentRepository = A.Dummy(); private readonly IContentWorkflow contentWorkflow = A.Fake(x => x.Wrapping(new DefaultContentWorkflow())); private readonly IAppProvider appProvider = A.Fake(); - private readonly IAppEntity app = A.Fake(); + private readonly IAppEntity appEntity = A.Fake(); private readonly LanguagesConfig languagesConfig = LanguagesConfig.Build(Language.DE); private readonly NamedContentData invalidData = @@ -92,10 +92,10 @@ namespace Squidex.Domain.Apps.Entities.Contents new NumberFieldProperties { IsRequired = false }) .ConfigureScripts(scripts); - A.CallTo(() => app.LanguagesConfig).Returns(languagesConfig); + A.CallTo(() => appEntity.LanguagesConfig).Returns(languagesConfig); - A.CallTo(() => appProvider.GetAppAsync(AppName)).Returns(app); - A.CallTo(() => appProvider.GetAppWithSchemaAsync(AppId, SchemaId)).Returns((app, schema)); + A.CallTo(() => appProvider.GetAppAsync(AppName)).Returns(appEntity); + A.CallTo(() => appProvider.GetAppWithSchemaAsync(AppId, SchemaId)).Returns((appEntity, schema)); A.CallTo(() => schema.SchemaDef).Returns(schemaDef); @@ -448,7 +448,7 @@ namespace Squidex.Domain.Apps.Entities.Contents var command = new ChangeContentStatus { Status = Status.Published, JobId = sut.Snapshot.ScheduleJob.Id }; - A.CallTo(() => contentWorkflow.CanMoveToAsync(A.Ignored, Status.Published)) + A.CallTo(() => contentWorkflow.CanMoveToAsync(A.Ignored, Status.Published, User)) .Returns(false); var result = await sut.ExecuteAsync(CreateContentCommand(command)); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs index 52117c964..00a7d83f5 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs @@ -53,13 +53,13 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly ClaimsPrincipal user; private readonly ClaimsIdentity identity = new ClaimsIdentity(); private readonly EdmModelBuilder modelBuilder = new EdmModelBuilder(new MemoryCache(Options.Create(new MemoryCacheOptions()))); - private readonly QueryContext context; + private readonly Context context; private readonly ContentQueryService sut; public static IEnumerable ApiStatusTests = new[] { - new object[] { StatusForApi.PublishedOnly, 0, new[] { Status.Published } }, - new object[] { StatusForApi.All, 1, null } + new object[] { 0, new[] { Status.Published } }, + new object[] { 1, null } }; public ContentQueryServiceTests() @@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Contents SetupEnricher(); - context = QueryContext.Create(app, user); + context = new Context(user, app); var options = Options.Create(new ContentOptions { DefaultPageSize = 30 }); @@ -221,16 +221,16 @@ namespace Squidex.Domain.Apps.Entities.Contents [Theory] [MemberData(nameof(ApiStatusTests))] - public async Task Should_return_single_content_for_api_with_transform(StatusForApi request, int includeDraft, Status[] status) + public async Task Should_return_single_content_for_api_with_transform(int unpublished, Status[] status) { var content = CreateContent(contentId); SetupClaims(isFrontend: false); SetupSchemaFound(); SetupScripting(contentId); - SetupContent(status, content, includeDraft == 1); + SetupContent(status, content, unpublished == 1); - var ctx = context.WithApiStatus(request); + var ctx = context.WithUnpublished(unpublished == 1); var result = await sut.FindContentAsync(ctx, schemaId.Name, contentId); @@ -299,7 +299,7 @@ namespace Squidex.Domain.Apps.Entities.Contents [Theory] [MemberData(nameof(ApiStatusTests))] - public async Task Should_query_contents_by_query_for_api_and_transform(StatusForApi request, int includeDraft, Status[] status) + public async Task Should_query_contents_by_query_for_api_and_transform(int unpublished, Status[] status) { const int count = 5, total = 200; @@ -308,9 +308,9 @@ namespace Squidex.Domain.Apps.Entities.Contents SetupClaims(isFrontend: false); SetupSchemaFound(); SetupScripting(contentId); - SetupContents(status, count, total, content, inDraft: false, includeDraft == 1); + SetupContents(status, count, total, content, inDraft: false, unpublished == 1); - var ctx = context.WithApiStatus(request); + var ctx = context.WithUnpublished(unpublished == 1); var result = await sut.QueryAsync(ctx, schemaId.Name, Q.Empty); @@ -359,7 +359,7 @@ namespace Squidex.Domain.Apps.Entities.Contents [Theory] [MemberData(nameof(ApiStatusTests))] - public async Task Should_query_contents_by_id_for_api_and_transform(StatusForApi request, int includeDraft, Status[] status) + public async Task Should_query_contents_by_id_for_api_and_transform(int unpublished, Status[] status) { const int count = 5, total = 200; @@ -368,9 +368,9 @@ namespace Squidex.Domain.Apps.Entities.Contents SetupClaims(isFrontend: false); SetupSchemaFound(); SetupScripting(ids.ToArray()); - SetupContents(status, total, ids, includeDraft == 1); + SetupContents(status, total, ids, unpublished == 1); - var ctx = context.WithApiStatus(request); + var ctx = context.WithUnpublished(unpublished == 1); var result = await sut.QueryAsync(ctx, schemaId.Name, Q.Empty.WithIds(ids)); @@ -405,7 +405,7 @@ namespace Squidex.Domain.Apps.Entities.Contents [Theory] [MemberData(nameof(ApiStatusTests))] - public async Task Should_query_all_contents_by_id_for_api_and_transform(StatusForApi request, int includeDraft, Status[] status) + public async Task Should_query_all_contents_by_id_for_api_and_transform(int unpublished, Status[] status) { const int count = 5; @@ -414,9 +414,9 @@ namespace Squidex.Domain.Apps.Entities.Contents SetupClaims(isFrontend: false); SetupSchemaFound(); SetupScripting(ids.ToArray()); - SetupContents(status, ids, includeDraft == 1); + SetupContents(status, ids, unpublished == 1); - var ctx = context.WithApiStatus(request); + var ctx = context.WithUnpublished(unpublished == 1); var result = await sut.QueryAsync(ctx, ids); @@ -527,7 +527,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private void SetupEnricher() { - A.CallTo(() => contentEnricher.EnrichAsync(A>.Ignored)) + A.CallTo(() => contentEnricher.EnrichAsync(A>.Ignored, user)) .ReturnsLazily(x => { var input = (IEnumerable)x.Arguments[0]; diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs index 20de4f522..6145d14ba 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs @@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = new ContentEntity { Status = Status.Published }; - var result = await sut.CanMoveToAsync(content, Status.Draft); + var result = await sut.CanMoveToAsync(content, Status.Draft, null); Assert.True(result); } @@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.Contents new StatusInfo(Status.Published, StatusColors.Published) }; - var result = await sut.GetNextsAsync(content); + var result = await sut.GetNextsAsync(content, null); result.Should().BeEquivalentTo(expected); } @@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Contents new StatusInfo(Status.Draft, StatusColors.Draft) }; - var result = await sut.GetNextsAsync(content); + var result = await sut.GetNextsAsync(content, null); result.Should().BeEquivalentTo(expected); } @@ -108,7 +108,7 @@ namespace Squidex.Domain.Apps.Entities.Contents new StatusInfo(Status.Draft, StatusColors.Draft) }; - var result = await sut.GetNextsAsync(content); + var result = await sut.GetNextsAsync(content, null); result.Should().BeEquivalentTo(expected); } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs new file mode 100644 index 000000000..037fcb694 --- /dev/null +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs @@ -0,0 +1,262 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using FakeItEasy; +using FluentAssertions; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.Scripting; +using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Infrastructure; +using Xunit; + +namespace Squidex.Domain.Apps.Entities.Contents +{ + public class DynamicContentWorkflowTests + { + private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); + private readonly IAppProvider appProvider = A.Fake(); + private readonly IAppEntity appEntity = A.Fake(); + private readonly DynamicContentWorkflow sut; + + private readonly Workflow workflow = new Workflow( + new Dictionary + { + [Status.Archived] = + new WorkflowStep( + new Dictionary + { + [Status.Draft] = new WorkflowTransition() + }, + StatusColors.Archived, true), + [Status.Draft] = + new WorkflowStep( + new Dictionary + { + [Status.Archived] = new WorkflowTransition(), + [Status.Published] = new WorkflowTransition("data.field.iv === 2", "Editor") + }, + StatusColors.Draft), + [Status.Published] = + new WorkflowStep( + new Dictionary + { + [Status.Archived] = new WorkflowTransition(), + [Status.Draft] = new WorkflowTransition() + }, + StatusColors.Published) + }, + Status.Draft); + + public DynamicContentWorkflowTests() + { + A.CallTo(() => appProvider.GetAppAsync(appId.Id)) + .Returns(appEntity); + + A.CallTo(() => appEntity.Workflows) + .Returns(Workflows.Empty.Set(workflow)); + + sut = new DynamicContentWorkflow(new JintScriptEngine(), appProvider); + } + + [Fact] + public async Task Should_draft_as_initial_status() + { + var expected = new StatusInfo(Status.Draft, StatusColors.Draft); + + var result = await sut.GetInitialStatusAsync(CreateSchema()); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task Should_check_is_valid_next() + { + var content = CreateContent(Status.Draft, 2); + + var result = await sut.CanMoveToAsync(content, Status.Published, User("Editor")); + + Assert.True(result); + } + + [Fact] + public async Task Should_not_allow_transition_if_role_is_not_allowed() + { + var content = CreateContent(Status.Draft, 2); + + var result = await sut.CanMoveToAsync(content, Status.Published, User("Developer")); + + Assert.False(result); + } + + [Fact] + public async Task Should_not_allow_transition_if_expression_does_not_evauate_to_true() + { + var content = CreateContent(Status.Draft, 4); + + var result = await sut.CanMoveToAsync(content, Status.Published, User("Editor")); + + Assert.False(result); + } + + [Fact] + public async Task Should_be_able_to_update_published() + { + var content = CreateContent(Status.Published, 2); + + var result = await sut.CanUpdateAsync(content); + + Assert.True(result); + } + + [Fact] + public async Task Should_be_able_to_update_draft() + { + var content = CreateContent(Status.Published, 2); + + var result = await sut.CanUpdateAsync(content); + + Assert.True(result); + } + + [Fact] + public async Task Should_not_be_able_to_update_archived() + { + var content = CreateContent(Status.Archived, 2); + + var result = await sut.CanUpdateAsync(content); + + Assert.False(result); + } + + [Fact] + public async Task Should_get_next_statuses_for_draft() + { + var content = CreateContent(Status.Draft, 2); + + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived) + }; + + var result = await sut.GetNextsAsync(content, User("Developer")); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task Should_limit_next_statuses_if_expression_does_not_evauate_to_true() + { + var content = CreateContent(Status.Draft, 4); + + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived) + }; + + var result = await sut.GetNextsAsync(content, User("Editor")); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task Should_limit_next_statuses_if_role_is_not_allowed() + { + var content = CreateContent(Status.Draft, 2); + + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived), + new StatusInfo(Status.Published, StatusColors.Published) + }; + + var result = await sut.GetNextsAsync(content, User("Editor")); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task Should_get_next_statuses_for_archived() + { + var content = CreateContent(Status.Archived, 2); + + var expected = new[] + { + new StatusInfo(Status.Draft, StatusColors.Draft) + }; + + var result = await sut.GetNextsAsync(content, null); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task Should_get_next_statuses_for_published() + { + var content = CreateContent(Status.Published, 2); + + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived), + new StatusInfo(Status.Draft, StatusColors.Draft) + }; + + var result = await sut.GetNextsAsync(content, null); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task Should_return_all_statuses() + { + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived), + new StatusInfo(Status.Draft, StatusColors.Draft), + new StatusInfo(Status.Published, StatusColors.Published) + }; + + var result = await sut.GetAllAsync(CreateSchema()); + + result.Should().BeEquivalentTo(expected); + } + + private ISchemaEntity CreateSchema() + { + var schema = A.Fake(); + + A.CallTo(() => schema.AppId).Returns(appId); + + return schema; + } + + private IContentEntity CreateContent(Status status, int value) + { + var data = + new NamedContentData() + .AddField("field", + new ContentFieldData() + .AddValue("iv", value)); + + return new ContentEntity { AppId = appId, Status = status, DataDraft = data }; + } + + private ClaimsPrincipal User(string role) + { + var userIdentity = new ClaimsIdentity(); + var userPrincipal = new ClaimsPrincipal(userIdentity); + + userIdentity.AddClaim(new Claim(ClaimTypes.Role, role)); + + return userPrincipal; + } + } +} diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs index 82cd8b87e..f07d13263 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs @@ -1017,14 +1017,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return A.That.Matches(x => x.Ids.Count == 1 && x.Ids[0] == contentId); } - private QueryContext MatchsAssetContext() + private Context MatchsAssetContext() { - return A.That.Matches(x => x.App == app && x.User == user); + return A.That.Matches(x => x.App == app && x.User == user); } - private QueryContext MatchsContentContext() + private Context MatchsContentContext() { - return A.That.Matches(x => x.App == app && x.User == user); + return A.That.Matches(x => x.App == app && x.User == user); } } } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs index 89f343e23..d14332136 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL protected readonly IJsonSerializer serializer = TestUtils.CreateSerializer(TypeNameHandling.None); protected readonly IDependencyResolver dependencyResolver; protected readonly IAppEntity app = A.Dummy(); - protected readonly QueryContext context; + protected readonly Context context; protected readonly ClaimsPrincipal user = new ClaimsPrincipal(); protected readonly IGraphQLService sut; @@ -88,7 +88,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL A.CallTo(() => app.Name).Returns(appName); A.CallTo(() => app.LanguagesConfig).Returns(LanguagesConfig.Build(Language.DE, Language.GermanGermany)); - context = QueryContext.Create(app, user); + context = new Context(user, app); A.CallTo(() => schema.Id).Returns(schemaId); A.CallTo(() => schema.SchemaDef).Returns(schemaDef); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs index ec1946256..b7e827dc3 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; using NodaTime; @@ -23,6 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { private readonly ISchemaEntity schema = A.Fake(); private readonly IContentWorkflow contentWorkflow = A.Fake(); + private readonly ClaimsPrincipal user = new ClaimsPrincipal(); private readonly Instant dueTimeInPast = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromHours(1)); [Fact] @@ -180,9 +182,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard SetupSingleton(false); var content = CreateContent(Status.Draft, false); - var command = new ChangeContentStatus { Status = Status.Published, DueTime = dueTimeInPast }; + var command = new ChangeContentStatus { Status = Status.Published, DueTime = dueTimeInPast, User = user }; - A.CallTo(() => contentWorkflow.CanMoveToAsync(content, command.Status)) + A.CallTo(() => contentWorkflow.CanMoveToAsync(content, command.Status, user)) .Returns(true); await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(schema, content, contentWorkflow, command), @@ -195,9 +197,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard SetupSingleton(false); var content = CreateContent(Status.Draft, false); - var command = new ChangeContentStatus { Status = Status.Published }; + var command = new ChangeContentStatus { Status = Status.Published, User = user }; - A.CallTo(() => contentWorkflow.CanMoveToAsync(content, command.Status)) + A.CallTo(() => contentWorkflow.CanMoveToAsync(content, command.Status, user)) .Returns(false); await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(schema, content, contentWorkflow, command), @@ -210,9 +212,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard SetupSingleton(false); var content = CreateContent(Status.Draft, false); - var command = new ChangeContentStatus { Status = Status.Published }; + var command = new ChangeContentStatus { Status = Status.Published, User = user }; - A.CallTo(() => contentWorkflow.CanMoveToAsync(content, command.Status)) + A.CallTo(() => contentWorkflow.CanMoveToAsync(content, command.Status, user)) .Returns(true); await GuardContent.CanChangeStatus(schema, content, contentWorkflow, command); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs b/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs index b48fb4f24..0cf89e968 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using FakeItEasy; using Squidex.Domain.Apps.Events; using Squidex.Infrastructure; @@ -26,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers private readonly IPersistence persistence1 = A.Fake>(); private readonly IPersistence persistence2 = A.Fake(); - protected RefToken User { get; } = new RefToken(RefTokenType.Subject, Guid.NewGuid().ToString()); + protected RefToken Actor { get; } = new RefToken(RefTokenType.Subject, Guid.NewGuid().ToString()); protected Guid AppId { get; } = Guid.NewGuid(); @@ -36,6 +37,8 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers protected string SchemaName { get; } = "my-schema"; + protected ClaimsPrincipal User { get; } = new ClaimsPrincipal(); + protected NamedId AppNamedId { get { return NamedId.Of(AppId, AppName); } @@ -87,7 +90,12 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers if (command.Actor == null) { - command.Actor = User; + command.Actor = Actor; + } + + if (command.User == null) + { + command.User = User; } if (command is IAppCommand appCommand && appCommand.AppId == null) @@ -110,7 +118,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers protected TEvent CreateEvent(TEvent @event) where TEvent : SquidexEvent { - @event.Actor = User; + @event.Actor = Actor; EnrichAppInfo(@event); EnrichSchemaInfo(@event); diff --git a/tests/Squidex.Infrastructure.Tests/Json/Newtonsoft/ReadOnlyDictionaryTests.cs b/tests/Squidex.Infrastructure.Tests/Json/Newtonsoft/ReadOnlyDictionaryTests.cs new file mode 100644 index 000000000..2d3ed2869 --- /dev/null +++ b/tests/Squidex.Infrastructure.Tests/Json/Newtonsoft/ReadOnlyDictionaryTests.cs @@ -0,0 +1,46 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using Newtonsoft.Json; +using Xunit; + +namespace Squidex.Infrastructure.Json.Newtonsoft +{ + public class ReadOnlyDictionaryTests + { + public sealed class MyClass + { + public IReadOnlyDictionary Values { get; set; } + } + + [Fact] + public void Should_serialize_and_deserialize_without_type_name() + { + var source = new MyClass + { + Values = new Dictionary + { + [2] = 4, + [3] = 9 + } + }; + + var serializerSettings = new JsonSerializerSettings + { + ContractResolver = new ConverterContractResolver() + }; + + var json = JsonConvert.SerializeObject(source, serializerSettings); + + var serialized = JsonConvert.DeserializeObject(json); + + Assert.DoesNotContain("$type", json); + Assert.Equal(2, serialized.Values.Count); + } + } +} diff --git a/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs b/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs index 9b95902d9..a07f0cfb7 100644 --- a/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs +++ b/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs @@ -38,7 +38,7 @@ namespace Squidex.Web actionExecutingContext = new ActionExecutingContext(actionContext, new List(), new Dictionary(), this); actionExecutingContext.HttpContext = httpContext; - actionExecutingContext.HttpContext.User = new ClaimsPrincipal(user); + actionExecutingContext.HttpContext.Context().User = new ClaimsPrincipal(user); next = () => { diff --git a/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs b/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs index 5c4ff17fe..8ad1aa5de 100644 --- a/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs +++ b/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs @@ -8,44 +8,43 @@ using System; using System.Threading.Tasks; using FakeItEasy; -using Microsoft.AspNetCore.Http; +using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; -using Squidex.Web.Pipeline; using Xunit; namespace Squidex.Web.CommandMiddlewares { public class EnrichWithAppIdCommandMiddlewareTests { - private readonly IHttpContextAccessor httpContextAccessor = A.Fake(); + private readonly IContextProvider contextProvider = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly HttpContext httpContext = new DefaultHttpContext(); + private readonly Context appContext = new Context(); private readonly EnrichWithAppIdCommandMiddleware sut; public EnrichWithAppIdCommandMiddlewareTests() { - A.CallTo(() => httpContextAccessor.HttpContext) - .Returns(httpContext); + A.CallTo(() => contextProvider.Context) + .Returns(appContext); - var appEntity = A.Fake(); + var app = A.Fake(); - A.CallTo(() => appEntity.Id).Returns(appId.Id); - A.CallTo(() => appEntity.Name).Returns(appId.Name); + A.CallTo(() => app.Id).Returns(appId.Id); + A.CallTo(() => app.Name).Returns(appId.Name); - httpContext.Features.Set(new AppResolver.AppFeature(appEntity)); + appContext.App = app; - sut = new EnrichWithAppIdCommandMiddleware(httpContextAccessor); + sut = new EnrichWithAppIdCommandMiddleware(contextProvider); } [Fact] public async Task Should_throw_exception_if_app_not_found() { - httpContext.Features.Set(new AppResolver.AppFeature(null)); + appContext.App = null; var command = new CreateContent(); var context = new CommandContext(command, commandBus); @@ -53,20 +52,6 @@ namespace Squidex.Web.CommandMiddlewares await Assert.ThrowsAsync(() => sut.HandleAsync(context)); } - [Fact] - public async Task Should_do_nothing_when_context_is_null() - { - A.CallTo(() => httpContextAccessor.HttpContext) - .Returns(null); - - var command = new CreateContent(); - var context = new CommandContext(command, commandBus); - - await sut.HandleAsync(context); - - Assert.Null(command.Actor); - } - [Fact] public async Task Should_assign_app_id_and_name_to_app_command() { diff --git a/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs b/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs index 4513b51b6..e3959732f 100644 --- a/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs +++ b/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs @@ -20,7 +20,6 @@ using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; -using Squidex.Web.Pipeline; using Xunit; namespace Squidex.Web.CommandMiddlewares @@ -44,54 +43,40 @@ namespace Squidex.Web.CommandMiddlewares A.CallTo(() => actionContextAccessor.ActionContext) .Returns(actionContext); - var appEntity = A.Fake(); + var app = A.Fake(); - A.CallTo(() => appEntity.Id).Returns(appId.Id); - A.CallTo(() => appEntity.Name).Returns(appId.Name); + A.CallTo(() => app.Id).Returns(appId.Id); + A.CallTo(() => app.Name).Returns(appId.Name); - httpContext.Features.Set(new AppResolver.AppFeature(appEntity)); + httpContext.Context().App = app; - var schemaEntity = A.Fake(); + var schema = A.Fake(); - A.CallTo(() => schemaEntity.Id).Returns(schemaId.Id); - A.CallTo(() => schemaEntity.SchemaDef).Returns(new Schema(schemaId.Name)); + A.CallTo(() => schema.Id).Returns(schemaId.Id); + A.CallTo(() => schema.SchemaDef).Returns(new Schema(schemaId.Name)); A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Name)) - .Returns(schemaEntity); + .Returns(schema); A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) - .Returns(schemaEntity); + .Returns(schema); sut = new EnrichWithSchemaIdCommandMiddleware(appProvider, actionContextAccessor); } [Fact] - public async Task Should_throw_exception_if_app_not_found() + public async Task Should_throw_exception_if_schema_not_found() { A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, "other-schema")) .Returns(Task.FromResult(null)); actionContext.RouteData.Values["name"] = "other-schema"; - var command = new CreateContent(); + var command = new CreateContent { AppId = appId }; var context = new CommandContext(command, commandBus); await Assert.ThrowsAsync(() => sut.HandleAsync(context)); } - [Fact] - public async Task Should_do_nothing_when_context_is_null() - { - A.CallTo(() => actionContextAccessor.ActionContext) - .Returns(null); - - var command = new CreateContent(); - var context = new CommandContext(command, commandBus); - - await sut.HandleAsync(context); - - Assert.Null(command.Actor); - } - [Fact] public async Task Should_do_nothing_when_route_has_no_parameter() { @@ -108,7 +93,7 @@ namespace Squidex.Web.CommandMiddlewares { actionContext.RouteData.Values["name"] = schemaId.Name; - var command = new CreateContent(); + var command = new CreateContent { AppId = appId }; var context = new CommandContext(command, commandBus); await sut.HandleAsync(context); @@ -119,9 +104,9 @@ namespace Squidex.Web.CommandMiddlewares [Fact] public async Task Should_assign_schema_id_and_name_from_id() { - actionContext.RouteData.Values["name"] = schemaId.Name; + actionContext.RouteData.Values["name"] = schemaId.Id; - var command = new CreateContent(); + var command = new CreateContent { AppId = appId }; var context = new CommandContext(command, commandBus); await sut.HandleAsync(context); @@ -142,19 +127,6 @@ namespace Squidex.Web.CommandMiddlewares Assert.Equal(schemaId.Id, command.SchemaId); } - [Fact] - public async Task Should_use_app_id_from_command() - { - actionContext.RouteData.Values["name"] = schemaId.Name; - - var command = new CreateContent { AppId = appId }; - var context = new CommandContext(command, commandBus); - - await sut.HandleAsync(context); - - Assert.Equal(schemaId, command.SchemaId); - } - [Fact] public async Task Should_not_override_schema_id() { diff --git a/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs b/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs index 2ee909d51..eb0ddb4eb 100644 --- a/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs +++ b/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs @@ -161,7 +161,7 @@ namespace Squidex.Web.Pipeline private void SetupApp() { - httpContext.Features.Set(new AppResolver.AppFeature(appEntity)); + httpContext.Context().App = appEntity; } } } \ No newline at end of file diff --git a/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs b/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs index 4aebe79cb..cf2ff94ec 100644 --- a/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs +++ b/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs @@ -86,7 +86,7 @@ namespace Squidex.Web.Pipeline await sut.OnActionExecutionAsync(actionExecutingContext, next); - Assert.Same(app, httpContext.Features.Get()?.App); + Assert.Same(app, httpContext.Context().App); Assert.True(user.Claims.Count() > 2); Assert.True(isNextCalled); } @@ -104,7 +104,7 @@ namespace Squidex.Web.Pipeline await sut.OnActionExecutionAsync(actionExecutingContext, next); - Assert.Same(app, httpContext.Features.Get()?.App); + Assert.Same(app, httpContext.Context().App); Assert.True(user.Claims.Count() > 2); Assert.True(isNextCalled); } @@ -124,7 +124,7 @@ namespace Squidex.Web.Pipeline await sut.OnActionExecutionAsync(actionExecutingContext, next); - Assert.Same(app, httpContext.Features.Get()?.App); + Assert.Same(app, httpContext.Context().App); Assert.Equal(2, user.Claims.Count()); Assert.True(isNextCalled); } @@ -161,34 +161,34 @@ namespace Squidex.Web.Pipeline private static IAppEntity CreateApp(string name, string appUser = null, string appClient = null) { - var app = A.Fake(); + var appEntity = A.Fake(); if (appUser != null) { - A.CallTo(() => app.Contributors) + A.CallTo(() => appEntity.Contributors) .Returns(AppContributors.Empty.Assign(appUser, Role.Owner)); } else { - A.CallTo(() => app.Contributors) + A.CallTo(() => appEntity.Contributors) .Returns(AppContributors.Empty); } if (appClient != null) { - A.CallTo(() => app.Clients) + A.CallTo(() => appEntity.Clients) .Returns(AppClients.Empty.Add(appClient, "secret")); } else { - A.CallTo(() => app.Clients) + A.CallTo(() => appEntity.Clients) .Returns(AppClients.Empty); } - A.CallTo(() => app.Roles) + A.CallTo(() => appEntity.Roles) .Returns(Roles.CreateDefaults(name)); - return app; + return appEntity; } } }