Browse Source

Azure queue action.

pull/240/head
Sebastian Stehle 8 years ago
parent
commit
2589cbef80
  1. 51
      src/Squidex.Domain.Apps.Core.Model/Rules/Actions/AzureQueueAction.cs
  2. 2
      src/Squidex.Domain.Apps.Core.Model/Rules/IRuleActionVisitor.cs
  3. 72
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/AzureQueueActionHandler.cs
  4. 13
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/SlackActionHandler.cs
  5. 22
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/WebhookActionHandler.cs
  6. 8
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs
  7. 1
      src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj
  8. 22
      src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleActionValidator.cs
  9. 36
      src/Squidex/Areas/Api/Controllers/Rules/Models/Actions/AzureQueueActionDto.cs
  10. 5
      src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleActionDtoFactory.cs
  11. 1
      src/Squidex/Areas/Api/Controllers/Rules/Models/RuleActionDto.cs
  12. 3
      src/Squidex/Config/Domain/ReadServices.cs
  13. 1
      src/Squidex/app/features/rules/declarations.ts
  14. 2
      src/Squidex/app/features/rules/module.ts
  15. 12
      src/Squidex/app/features/rules/pages/rules/actions/algolia-action.component.html
  16. 29
      src/Squidex/app/features/rules/pages/rules/actions/azure-queue-action.component.html
  17. 2
      src/Squidex/app/features/rules/pages/rules/actions/azure-queue-action.component.scss
  18. 61
      src/Squidex/app/features/rules/pages/rules/actions/azure-queue-action.component.ts
  19. 8
      src/Squidex/app/features/rules/pages/rules/actions/slack-action.component.html
  20. 8
      src/Squidex/app/features/rules/pages/rules/actions/webhook-action.component.html
  21. 6
      src/Squidex/app/features/rules/pages/rules/rule-wizard.component.html
  22. 1
      src/Squidex/app/shared/services/rules.service.ts
  23. 5
      src/Squidex/app/theme/_rules.scss
  24. 16
      src/Squidex/app/theme/icomoon/demo.html
  25. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.eot
  26. 2
      src/Squidex/app/theme/icomoon/fonts/icomoon.svg
  27. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.ttf
  28. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.woff
  29. 2
      src/Squidex/app/theme/icomoon/selection.json
  30. 13
      src/Squidex/app/theme/icomoon/style.css

51
src/Squidex.Domain.Apps.Core.Model/Rules/Actions/AzureQueueAction.cs

@ -0,0 +1,51 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Rules.Actions
{
[TypeName(nameof(AzureQueueAction))]
public sealed class AzureQueueAction : RuleAction
{
private string connectionString;
private string queue;
public string ConnectionString
{
get
{
return connectionString;
}
set
{
ThrowIfFrozen();
connectionString = value;
}
}
public string Queue
{
get
{
return queue;
}
set
{
ThrowIfFrozen();
queue = value;
}
}
public override T Accept<T>(IRuleActionVisitor<T> visitor)
{
return visitor.Visit(this);
}
}
}

2
src/Squidex.Domain.Apps.Core.Model/Rules/IRuleActionVisitor.cs

@ -13,6 +13,8 @@ namespace Squidex.Domain.Apps.Core.Rules
{
T Visit(AlgoliaAction action);
T Visit(AzureQueueAction action);
T Visit(SlackAction action);
T Visit(WebhookAction action);

72
src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/AzureQueueActionHandler.cs

@ -0,0 +1,72 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Actions;
using Squidex.Domain.Apps.Events;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Core.HandleRules.Actions
{
public sealed class AzureQueueActionHandler : RuleActionHandler<AzureQueueAction>
{
private readonly ConcurrentDictionary<(string ConnectionString, string QueueName), CloudQueue> queues = new ConcurrentDictionary<(string ConnectionString, string QueueName), CloudQueue>();
private readonly RuleEventFormatter formatter;
public AzureQueueActionHandler(RuleEventFormatter formatter)
{
Guard.NotNull(formatter, nameof(formatter));
this.formatter = formatter;
}
protected override (string Description, RuleJobData Data) CreateJob(Envelope<AppEvent> @event, string eventName, AzureQueueAction action)
{
var body = formatter.ToRouteData(@event, eventName);
var ruleDescription = $"Send event to azure queue '{action.Queue}'";
var ruleData = new RuleJobData
{
["QueueConnectionString"] = action.ConnectionString,
["QueueName"] = action.Queue,
["MessageBody"] = body
};
return (ruleDescription, ruleData);
}
public override async Task<(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job)
{
var queueConnectionString = job["QueueConnectionString"].Value<string>();
var queueName = job["QueueName"].Value<string>();
var queue = queues.GetOrAdd((queueConnectionString, queueName), s =>
{
var storageAccount = CloudStorageAccount.Parse(queueConnectionString);
var queueClient = storageAccount.CreateCloudQueueClient();
var queueRef = queueClient.GetQueueReference(queueName);
return queueRef;
});
var messageBody = job["MessageBody"].ToString(Formatting.Indented);
await queue.AddMessageAsync(new CloudQueueMessage(messageBody));
return ("Completed", null);
}
}
}

13
src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/SlackActionHandler.cs

@ -49,31 +49,30 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Actions
private JObject CreatePayload(Envelope<AppEvent> @event, string text)
{
return new JObject(
new JProperty("text", formatter.FormatString(text, @event)));
return new JObject(new JProperty("text", formatter.FormatString(text, @event)));
}
public override async Task<(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job)
{
var requestBody = job["RequestBody"].ToString(Formatting.Indented);
var request = BuildRequest(job, requestBody);
var requestMsg = BuildRequest(job, requestBody);
HttpResponseMessage response = null;
try
{
response = await Client.SendAsync(request);
response = await Client.SendAsync(requestMsg);
var responseString = await response.Content.ReadAsStringAsync();
var requestDump = DumpFormatter.BuildDump(request, response, requestBody, responseString, TimeSpan.Zero, false);
var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, responseString, TimeSpan.Zero, false);
return (requestDump, null);
}
catch (Exception ex)
{
if (request != null)
if (requestMsg != null)
{
var requestDump = DumpFormatter.BuildDump(request, response, requestBody, ex.ToString(), TimeSpan.Zero, false);
var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, ex.ToString(), TimeSpan.Zero, false);
return (requestDump, ex);
}

22
src/Squidex.Domain.Apps.Core.Operations/HandleRules/Actions/WebhookActionHandler.cs

@ -35,11 +35,11 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Actions
protected override (string Description, RuleJobData Data) CreateJob(Envelope<AppEvent> @event, string eventName, WebhookAction action)
{
var body = CreatePayload(@event, eventName);
var body = formatter.ToRouteData(@event, eventName);
var signature = $"{body.ToString(Formatting.Indented)}{action.SharedSecret}".Sha256Base64();
var ruleDescription = $"Send event to webhook {action.Url}";
var ruleDescription = $"Send event to webhook '{action.Url}'";
var ruleData = new RuleJobData
{
["RequestUrl"] = action.Url,
@ -50,18 +50,10 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Actions
return (ruleDescription, ruleData);
}
private JObject CreatePayload(Envelope<AppEvent> @event, string eventName)
{
return new JObject(
new JProperty("type", eventName),
new JProperty("payload", formatter.ToRouteData(@event.Payload)),
new JProperty("timestamp", @event.Headers.Timestamp().ToString()));
}
public override async Task<(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job)
{
var requestBody = job["RequestBody"].ToString(Formatting.Indented);
var request = BuildRequest(job, requestBody);
var requestMsg = BuildRequest(job, requestBody);
HttpResponseMessage response = null;
@ -69,19 +61,19 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Actions
{
using (var client = new HttpClient { Timeout = Timeout })
{
response = await client.SendAsync(request);
response = await client.SendAsync(requestMsg);
var responseString = await response.Content.ReadAsStringAsync();
var requestDump = DumpFormatter.BuildDump(request, response, requestBody, responseString, TimeSpan.Zero, false);
var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, responseString, TimeSpan.Zero, false);
return (requestDump, null);
}
}
catch (Exception ex)
{
if (request != null)
if (requestMsg != null)
{
var requestDump = DumpFormatter.BuildDump(request, response, requestBody, ex.ToString(), TimeSpan.Zero, false);
var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, ex.ToString(), TimeSpan.Zero, false);
return (requestDump, ex);
}

8
src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs

@ -43,6 +43,14 @@ namespace Squidex.Domain.Apps.Core.HandleRules
return JToken.FromObject(value, serializer);
}
public virtual JToken ToRouteData(Envelope<AppEvent> @event, string eventName)
{
return new JObject(
new JProperty("type", eventName),
new JProperty("payload", JToken.FromObject(@event.Payload, serializer)),
new JProperty("timestamp", @event.Headers.Timestamp().ToString()));
}
public virtual string FormatString(string text, Envelope<AppEvent> @event)
{
var sb = new StringBuilder(text);

1
src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj

@ -23,6 +23,7 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
<PackageReference Include="System.Collections.Immutable" Version="1.4.0" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
<PackageReference Include="WindowsAzure.Storage" Version="8.7.0" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet>

22
src/Squidex.Domain.Apps.Entities/Rules/Guards/RuleActionValidator.cs

@ -6,6 +6,7 @@
// ==========================================================================
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Actions;
@ -46,6 +47,27 @@ namespace Squidex.Domain.Apps.Entities.Rules.Guards
return Task.FromResult<IEnumerable<ValidationError>>(errors);
}
public Task<IEnumerable<ValidationError>> Visit(AzureQueueAction action)
{
var errors = new List<ValidationError>();
if (string.IsNullOrWhiteSpace(action.ConnectionString))
{
errors.Add(new ValidationError("Connection string must be defined.", nameof(action.ConnectionString)));
}
if (string.IsNullOrWhiteSpace(action.Queue))
{
errors.Add(new ValidationError("Queue must be defined.", nameof(action.Queue)));
}
else if (!Regex.IsMatch(action.Queue, "^[a-z][a-z0-9]{2,}(\\-[a-z0-9]+)*$"))
{
errors.Add(new ValidationError("Queue must be valid azure queue name.", nameof(action.Queue)));
}
return Task.FromResult<IEnumerable<ValidationError>>(errors);
}
public Task<IEnumerable<ValidationError>> Visit(SlackAction action)
{
var errors = new List<ValidationError>();

36
src/Squidex/Areas/Api/Controllers/Rules/Models/Actions/AzureQueueActionDto.cs

@ -0,0 +1,36 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.ComponentModel.DataAnnotations;
using NJsonSchema.Annotations;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Actions;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Areas.Api.Controllers.Rules.Models.Actions
{
[JsonSchema("AzureQueue")]
public class AzureQueueActionDto : RuleActionDto
{
/// <summary>
/// The connection string to the storage account.
/// </summary>
[Required]
public string ConnectionString { get; set; }
/// <summary>
/// The queue name.
/// </summary>
[Required]
public string Queue { get; set; }
public override RuleAction ToAction()
{
return SimpleMapper.Map(this, new AzureQueueAction());
}
}
}

5
src/Squidex/Areas/Api/Controllers/Rules/Models/Converters/RuleActionDtoFactory.cs

@ -30,6 +30,11 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models.Converters
return SimpleMapper.Map(action, new AlgoliaActionDto());
}
public RuleActionDto Visit(AzureQueueAction action)
{
return SimpleMapper.Map(action, new AzureQueueActionDto());
}
public RuleActionDto Visit(SlackAction action)
{
return SimpleMapper.Map(action, new SlackActionDto());

1
src/Squidex/Areas/Api/Controllers/Rules/Models/RuleActionDto.cs

@ -14,6 +14,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models
{
[JsonConverter(typeof(JsonInheritanceConverter), "actionType")]
[KnownType(typeof(AlgoliaActionDto))]
[KnownType(typeof(AzureQueueActionDto))]
[KnownType(typeof(SlackActionDto))]
[KnownType(typeof(WebhookActionDto))]
public abstract class RuleActionDto

3
src/Squidex/Config/Domain/ReadServices.cs

@ -98,6 +98,9 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<AlgoliaActionHandler>()
.As<IRuleActionHandler>();
services.AddSingletonAs<AzureQueueActionHandler>()
.As<IRuleActionHandler>();
services.AddSingletonAs<SlackActionHandler>()
.As<IRuleActionHandler>();

1
src/Squidex/app/features/rules/declarations.ts

@ -6,6 +6,7 @@
*/
export * from './pages/rules/actions/algolia-action.component';
export * from './pages/rules/actions/azure-queue-action.component';
export * from './pages/rules/actions/slack-action.component';
export * from './pages/rules/actions/webhook-action.component';
export * from './pages/rules/triggers/content-changed-trigger.component';

2
src/Squidex/app/features/rules/module.ts

@ -16,6 +16,7 @@ import {
import {
AlgoliaActionComponent,
AzureQueueActionComponent,
ContentChangedTriggerComponent,
RuleEventsPageComponent,
RulesPageComponent,
@ -52,6 +53,7 @@ const routes: Routes = [
],
declarations: [
AlgoliaActionComponent,
AzureQueueActionComponent,
ContentChangedTriggerComponent,
RuleEventsPageComponent,
RulesPageComponent,

12
src/Squidex/app/features/rules/pages/rules/actions/algolia-action.component.html

@ -1,8 +1,8 @@
<form [formGroup]="actionForm" class="form-horizontal" (ngSubmit)="save()">
<div class="form-group row">
<label class="col col-2 col-form-label" for="appId">App ID</label>
<label class="col col-3 col-form-label" for="appId">App ID</label>
<div class="col col-10">
<div class="col col-9">
<sqx-control-errors for="text" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="appId" formControlName="appId" />
@ -14,9 +14,9 @@
</div>
<div class="form-group row">
<label class="col col-2 col-form-label" for="apiKey">Api Key</label>
<label class="col col-3 col-form-label" for="apiKey">Api Key</label>
<div class="col col-10">
<div class="col col-9">
<sqx-control-errors for="apiKey" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="apiKey" formControlName="apiKey" />
@ -28,9 +28,9 @@
</div>
<div class="form-group row">
<label class="col col-2 col-form-label" for="sharedSecret">Index Name</label>
<label class="col col-3 col-form-label" for="sharedSecret">Index Name</label>
<div class="col col-10">
<div class="col col-9">
<sqx-control-errors for="indexName" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="indexName" formControlName="indexName" />

29
src/Squidex/app/features/rules/pages/rules/actions/azure-queue-action.component.html

@ -0,0 +1,29 @@
<form [formGroup]="actionForm" class="form-horizontal" (ngSubmit)="save()">
<div class="form-group row">
<label class="col col-3 col-form-label" for="queue">Connection String</label>
<div class="col col-9">
<sqx-control-errors for="text" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="connectionString" formControlName="connectionString" />
<small class="form-text text-muted">
The connection string to the storage account.
</small>
</div>
</div>
<div class="form-group row">
<label class="col col-3 col-form-label" for="queue">Queue Name</label>
<div class="col col-9">
<sqx-control-errors for="queue" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="queue" formControlName="queue" />
<small class="form-text text-muted">
The name of the queue.
</small>
</div>
</div>
</form>

2
src/Squidex/app/features/rules/pages/rules/actions/azure-queue-action.component.scss

@ -0,0 +1,2 @@
@import '_vars';
@import '_mixins';

61
src/Squidex/app/features/rules/pages/rules/actions/azure-queue-action.component.ts

@ -0,0 +1,61 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { ValidatorsEx } from 'shared';
@Component({
selector: 'sqx-azure-queue-action',
styleUrls: ['./azure-queue-action.component.scss'],
templateUrl: './azure-queue-action.component.html'
})
export class AzureQueueActionComponent implements OnInit {
@Input()
public action: any;
@Output()
public actionChanged = new EventEmitter<object>();
public actionFormSubmitted = false;
public actionForm =
this.formBuilder.group({
connectionString: ['',
[
Validators.required
]],
queue: ['squidex',
[
Validators.required,
ValidatorsEx.pattern('[a-z][a-z0-9]{2,}(\-[a-z0-9]+)*', 'Name must be a valid azure queue name.')
]]
});
constructor(
private readonly formBuilder: FormBuilder
) {
}
public ngOnInit() {
this.action = Object.assign({}, { connectionString: '', queue: 'squidex' }, this.action || {});
this.actionFormSubmitted = false;
this.actionForm.reset();
this.actionForm.setValue(this.action);
}
public save() {
this.actionFormSubmitted = true;
if (this.actionForm.valid) {
const action = this.actionForm.value;
this.actionChanged.emit(action);
}
}
}

8
src/Squidex/app/features/rules/pages/rules/actions/slack-action.component.html

@ -1,8 +1,8 @@
<form [formGroup]="actionForm" class="form-horizontal" (ngSubmit)="save()">
<div class="form-group row">
<label class="col col-2 col-form-label" for="webhookUrl">Webhook Url</label>
<label class="col col-3 col-form-label" for="webhookUrl">Webhook Url</label>
<div class="col col-10">
<div class="col col-9">
<sqx-control-errors for="webhookUrl" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="webhookUrl" class="form-control" id="webhookUrl" formControlName="webhookUrl" />
@ -14,9 +14,9 @@
</div>
<div class="form-group row">
<label class="col col-2 col-form-label" for="text">Text</label>
<label class="col col-3 col-form-label" for="text">Text</label>
<div class="col col-10">
<div class="col col-9">
<sqx-control-errors for="text" [submitted]="actionFormSubmitted"></sqx-control-errors>
<textarea class="form-control" id="text" formControlName="text"></textarea>

8
src/Squidex/app/features/rules/pages/rules/actions/webhook-action.component.html

@ -1,8 +1,8 @@
<form [formGroup]="actionForm" class="form-horizontal" (ngSubmit)="save()">
<div class="form-group row">
<label class="col col-2 col-form-label" for="url">Url</label>
<label class="col col-3 col-form-label" for="url">Url</label>
<div class="col col-10">
<div class="col col-9">
<sqx-control-errors for="url" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="url" class="form-control" id="url" formControlName="url" />
@ -14,9 +14,9 @@
</div>
<div class="form-group row">
<label class="col col-2 col-form-label" for="sharedSecret">Secret</label>
<label class="col col-3 col-form-label" for="sharedSecret">Secret</label>
<div class="col col-10">
<div class="col col-9">
<sqx-control-errors for="sharedSecret" [submitted]="actionFormSubmitted"></sqx-control-errors>
<input type="text" class="form-control" id="sharedSecret" formControlName="sharedSecret" />

6
src/Squidex/app/features/rules/pages/rules/rule-wizard.component.html

@ -68,6 +68,12 @@
(actionChanged)="selectAction($event)">
</sqx-algolia-action>
</div>
<div *ngSwitchCase="'AzureQueue'">
<sqx-azure-queue-action #actionControl
[action]="action"
(actionChanged)="selectAction($event)">
</sqx-azure-queue-action>
</div>
<div *ngSwitchCase="'Slack'">
<sqx-slack-action #actionControl
[action]="action"

1
src/Squidex/app/shared/services/rules.service.ts

@ -26,6 +26,7 @@ export const ruleTriggers: any = {
export const ruleActions: any = {
'Algolia': 'Populate Algolia Index',
'AzureQueue': 'Send to Azure Queue',
'Slack': 'Send to Slack',
'Webhook': 'Send Webhook'
};

5
src/Squidex/app/theme/_rules.scss

@ -6,6 +6,7 @@ $trigger-content-changed: #3389ff;
$action-webhook: #4bb958;
$action-algolia: #0d9bf9;
$action-slack: #5c3a58;
$action-azure: #55b3ff;
@mixin build-element($color) {
& {
@ -51,6 +52,10 @@ $action-slack: #5c3a58;
@include build-element($trigger-content-changed);
}
.rule-element-AzureQueue {
@include build-element($action-azure);
}
.rule-element-Algolia {
@include build-element($action-algolia);
}

16
src/Squidex/app/theme/icomoon/demo.html

@ -1299,6 +1299,22 @@
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs3">
<div class="clearfix bshadow0 pbs">
<span class="icon-action-AzureQueue">
</span>
<span class="mls"> icon-action-AzureQueue</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e940" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe940;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs3">
<div class="clearfix bshadow0 pbs">
<span class="icon-pause">

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.eot

Binary file not shown.

2
src/Squidex/app/theme/icomoon/fonts/icomoon.svg

@ -71,7 +71,7 @@
<glyph unicode="&#xe93d;" glyph-name="bug" horiz-adv-x="951" d="M932.571 402.286c0-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.571v512h-73.143v-512c-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.571h128v168l-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.857v-168h128c20 0 36.571-16.571 36.571-36.571zM658.286 731.428h-365.714c0 101.143 81.714 182.857 182.857 182.857s182.857-81.714 182.857-182.857z" />
<glyph unicode="&#xe93e;" glyph-name="download" d="M640 853.334q78 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 512q17.667 0 30.167-12.5t12.5-30.167v-281l55 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.333v281q0 17.667 12.5 30.167t30.167 12.5z" />
<glyph unicode="&#xe93f;" glyph-name="document-unpublish" d="M358.4 848.457c-28.314 0-51.2-22.886-51.2-51.2v-153.6h51.2v153.6h307.2v-153.6c0-28.314 22.886-51.2 51.2-51.2h153.6v-512h-358.4v-51.2h358.4c28.314 0 51.2 22.886 51.2 51.2v548.2l-219.8 219.8h-292.2zM716.8 761.057l117.4-117.4h-117.4zM332.8 490.057l-230.4-256v-51.2h102.4v-153.6h256v153.6h102.4v51.2zM332.8 413.557l161.5-179.5h-84.7v-153.6h-153.6v153.6h-84.7zM102.4 593.325h460.8v-52.068h-460.8v52.068z" />
<glyph unicode="&#xe940;" glyph-name="microsoft" d="M0.35 448l-0.35 312.074 384 52.144v-364.218zM448 821.518l511.872 74.482v-448h-511.872zM959.998 384l-0.126-448-511.872 72.016v375.984zM384 16.164l-383.688 52.594-0.020 315.242h383.708z" />
<glyph unicode="&#xe940;" glyph-name="microsoft, action-AzureQueue" d="M0.35 448l-0.35 312.074 384 52.144v-364.218zM448 821.518l511.872 74.482v-448h-511.872zM959.998 384l-0.126-448-511.872 72.016v375.984zM384 16.164l-383.688 52.594-0.020 315.242h383.708z" />
<glyph unicode="&#xe941;" glyph-name="github" d="M512 960c-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" />
<glyph unicode="&#xe942;" glyph-name="checkmark" d="M927.936 687.008l-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" />
<glyph unicode="&#xe943;" glyph-name="elapsed" d="M512.002 766.788v65.212h128v64c0 35.346-28.654 64-64.002 64h-191.998c-35.346 0-64-28.654-64-64v-64h128v-65.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 125.726c-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" />

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.ttf

Binary file not shown.

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.woff

Binary file not shown.

2
src/Squidex/app/theme/icomoon/selection.json

@ -2121,7 +2121,7 @@
"id": 1,
"prevSize": 32,
"code": 59712,
"name": "microsoft"
"name": "microsoft, action-AzureQueue"
},
"setIdx": 2,
"setId": 1,

13
src/Squidex/app/theme/icomoon/style.css

@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?fb43dg');
src: url('fonts/icomoon.eot?fb43dg#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?fb43dg') format('truetype'),
url('fonts/icomoon.woff?fb43dg') format('woff'),
url('fonts/icomoon.svg?fb43dg#icomoon') format('svg');
src: url('fonts/icomoon.eot?knmn0p');
src: url('fonts/icomoon.eot?knmn0p#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?knmn0p') format('truetype'),
url('fonts/icomoon.woff?knmn0p') format('woff'),
url('fonts/icomoon.svg?knmn0p#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
@ -265,6 +265,9 @@
.icon-microsoft:before {
content: "\e940";
}
.icon-action-AzureQueue:before {
content: "\e940";
}
.icon-pause:before {
content: "\e92f";
}

Loading…
Cancel
Save