Browse Source

Admin feature.

pull/311/head
Sebastian 8 years ago
parent
commit
4a712a8a04
  1. 6
      src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs
  2. 7
      src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs
  3. 213
      src/Squidex.Domain.Apps.Entities/Backup/AppCleanerGrain.cs
  4. 5
      src/Squidex.Domain.Apps.Entities/Backup/BackupHandler.cs
  5. 16
      src/Squidex.Domain.Apps.Entities/Backup/CleanerStatus.cs
  6. 44
      src/Squidex.Domain.Apps.Entities/Backup/EnqueueAppToCleanerMiddleware.cs
  7. 20
      src/Squidex.Domain.Apps.Entities/Backup/IAppCleanerGrain.cs
  8. 24
      src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs
  9. 5
      src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs
  10. 34
      src/Squidex.Domain.Apps.Entities/History/BackupHistory.cs
  11. 14
      src/Squidex.Domain.Apps.Entities/Rules/BackupRules.cs
  12. 14
      src/Squidex.Domain.Apps.Entities/Schemas/BackupSchemas.cs
  13. 18
      src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs
  14. 6
      src/Squidex/Config/Domain/EntitiesServices.cs
  15. 2
      src/Squidex/Config/Orleans/SiloWrapper.cs
  16. 5
      src/Squidex/app/features/administration/administration-area.component.html
  17. 1
      src/Squidex/app/features/administration/declarations.ts
  18. 6
      src/Squidex/app/features/administration/module.ts
  19. 65
      src/Squidex/app/features/administration/pages/restore/restore-page.component.html
  20. 1
      src/Squidex/app/features/administration/pages/restore/restore-page.component.scss
  21. 0
      src/Squidex/app/features/administration/pages/restore/restore-page.component.ts
  22. 3
      src/Squidex/app/features/apps/declarations.ts
  23. 9
      src/Squidex/app/features/apps/module.ts
  24. 4
      src/Squidex/app/features/apps/pages/apps-page.component.html
  25. 4
      src/Squidex/app/features/apps/pages/apps-page.component.scss
  26. 59
      src/Squidex/app/features/apps/pages/restore-page.component.html
  27. 18
      src/Squidex/app/theme/icomoon/demo.html
  28. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.eot
  29. 1
      src/Squidex/app/theme/icomoon/fonts/icomoon.svg
  30. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.ttf
  31. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.woff
  32. 219
      src/Squidex/app/theme/icomoon/selection.json
  33. 13
      src/Squidex/app/theme/icomoon/style.css
  34. 48
      tests/Squidex.Domain.Apps.Entities.Tests/Backup/EnqueueAppToCleanerMiddlewareTests.cs

6
src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs

@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Orleans; using Orleans;
using Squidex.Domain.Apps.Entities.Apps.Indexes; using Squidex.Domain.Apps.Entities.Apps.Indexes;
using Squidex.Domain.Apps.Entities.Apps.State;
using Squidex.Domain.Apps.Entities.Backup; using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Apps;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -37,11 +36,6 @@ namespace Squidex.Domain.Apps.Entities.Apps
this.grainFactory = grainFactory; this.grainFactory = grainFactory;
} }
public override Task RemoveAsync(Guid appId)
{
return RemoveSnapshotAsync<AppState>(appId);
}
public async override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader) public async override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader)
{ {
switch (@event.Payload) switch (@event.Payload)

7
src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs

@ -52,13 +52,6 @@ namespace Squidex.Domain.Apps.Entities.Assets
this.tagService = tagService; this.tagService = tagService;
} }
public override async Task RemoveAsync(Guid appId)
{
await tagService.ClearAsync(appId, TagGroups.Assets);
await assetRepository.RemoveAsync(appId);
}
public override Task BackupEventAsync(EventData @event, Guid appId, BackupWriter writer) public override Task BackupEventAsync(EventData @event, Guid appId, BackupWriter writer)
{ {
if (@event.Type == "AssetCreatedEvent" || if (@event.Type == "AssetCreatedEvent" ||

213
src/Squidex.Domain.Apps.Entities/Backup/AppCleanerGrain.cs

@ -1,213 +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.Linq;
using System.Threading.Tasks;
using Orleans;
using Orleans.Concurrency;
using Orleans.Runtime;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.States;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Domain.Apps.Entities.Backup
{
[Reentrant]
public sealed class AppCleanerGrain : GrainOfString, IRemindable, IAppCleanerGrain
{
private readonly IGrainFactory grainFactory;
private readonly IStore<Guid> store;
private readonly IEventStore eventStore;
private readonly IEnumerable<BackupHandler> handlers;
private readonly ISemanticLog log;
private IPersistence<State> persistence;
private bool isCleaning;
private State state = new State();
[CollectionName("AppCleaner")]
public sealed class State
{
public HashSet<Guid> Apps { get; set; } = new HashSet<Guid>();
public HashSet<Guid> FailedApps { get; set; } = new HashSet<Guid>();
}
public AppCleanerGrain(IGrainFactory grainFactory, IEventStore eventStore, IStore<Guid> store, IEnumerable<BackupHandler> handlers, ISemanticLog log)
{
Guard.NotNull(grainFactory, nameof(grainFactory));
Guard.NotNull(store, nameof(store));
Guard.NotNull(handlers, nameof(handlers));
Guard.NotNull(eventStore, nameof(eventStore));
Guard.NotNull(log, nameof(log));
this.grainFactory = grainFactory;
this.store = store;
this.handlers = handlers;
this.log = log;
this.eventStore = eventStore;
}
public async override Task OnActivateAsync(string key)
{
await RegisterOrUpdateReminder("Default", TimeSpan.Zero, TimeSpan.FromMinutes(1));
persistence = store.WithSnapshots<AppCleanerGrain, State, Guid>(Guid.Empty, s =>
{
state = s;
});
await ReadAsync();
Clean();
}
public Task EnqueueAppAsync(Guid appId)
{
if (appId != Guid.Empty)
{
state.Apps.Add(appId);
Clean();
}
return WriteAsync();
}
public Task ActivateAsync()
{
Clean();
return TaskHelper.Done;
}
public Task ReceiveReminder(string reminderName, TickStatus status)
{
Clean();
return TaskHelper.Done;
}
public Task<CleanerStatus> GetStatusAsync(Guid appId)
{
if (state.Apps.Contains(appId))
{
return Task.FromResult(CleanerStatus.Cleaning);
}
if (state.FailedApps.Contains(appId))
{
return Task.FromResult(CleanerStatus.Failed);
}
return Task.FromResult(CleanerStatus.Cleaned);
}
private void Clean()
{
CleanAsync().Forget();
}
private async Task CleanAsync()
{
if (isCleaning)
{
return;
}
isCleaning = true;
try
{
foreach (var appId in state.Apps.ToList())
{
await CleanupAppAsync(appId);
}
}
finally
{
isCleaning = false;
}
}
private async Task CleanupAppAsync(Guid appId)
{
using (Profiler.StartSession())
{
try
{
log.LogInformation(w => w
.WriteProperty("action", "cleanApp")
.WriteProperty("status", "started")
.WriteProperty("appId", appId.ToString()));
await CleanupAppCoreAsync(appId);
log.LogInformation(w =>
{
w.WriteProperty("action", "cleanApp");
w.WriteProperty("status", "completed");
w.WriteProperty("appId", appId.ToString());
Profiler.Session?.Write(w);
});
}
catch (Exception ex)
{
state.FailedApps.Add(appId);
log.LogError(ex, w =>
{
w.WriteProperty("action", "cleanApp");
w.WriteProperty("status", "failed");
w.WriteProperty("appId", appId.ToString());
Profiler.Session?.Write(w);
});
}
finally
{
state.Apps.Remove(appId);
await WriteAsync();
}
}
}
private async Task CleanupAppCoreAsync(Guid appId)
{
using (Profiler.Trace("DeleteEvents"))
{
await eventStore.DeleteManyAsync("AppId", appId.ToString());
}
foreach (var handler in handlers)
{
using (Profiler.TraceMethod(handler.GetType(), nameof(BackupHandler.RemoveAsync)))
{
await handler.RemoveAsync(appId);
}
}
}
private async Task ReadAsync()
{
await persistence.ReadAsync();
}
private async Task WriteAsync()
{
await persistence.WriteSnapshotAsync(state);
}
}
}

5
src/Squidex.Domain.Apps.Entities/Backup/BackupHandler.cs

@ -50,10 +50,5 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
return TaskHelper.Done; return TaskHelper.Done;
} }
public virtual Task RemoveAsync(Guid appId)
{
return TaskHelper.Done;
}
} }
} }

16
src/Squidex.Domain.Apps.Entities/Backup/CleanerStatus.cs

@ -1,16 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Entities.Backup
{
public enum CleanerStatus
{
Cleaned,
Cleaning,
Failed
}
}

44
src/Squidex.Domain.Apps.Entities/Backup/EnqueueAppToCleanerMiddleware.cs

@ -1,44 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Orleans;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Domain.Apps.Entities.Backup
{
public sealed class EnqueueAppToCleanerMiddleware : ICommandMiddleware
{
private readonly IAppCleanerGrain cleaner;
public EnqueueAppToCleanerMiddleware(IGrainFactory grainFactory)
{
Guard.NotNull(grainFactory, nameof(grainFactory));
cleaner = grainFactory.GetGrain<IAppCleanerGrain>(SingleGrain.Id);
}
public async Task HandleAsync(CommandContext context, Func<Task> next)
{
if (context.IsCompleted)
{
switch (context.Command)
{
case ArchiveApp archiveApp:
await cleaner.EnqueueAppAsync(archiveApp.AppId);
break;
}
}
await next();
}
}
}

20
src/Squidex.Domain.Apps.Entities/Backup/IAppCleanerGrain.cs

@ -1,20 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Domain.Apps.Entities.Backup
{
public interface IAppCleanerGrain : IBackgroundGrain
{
Task EnqueueAppAsync(Guid appId);
Task<CleanerStatus> GetStatusAsync(Guid appId);
}
}

24
src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs

@ -30,7 +30,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
private readonly IAssetStore assetStore; private readonly IAssetStore assetStore;
private readonly IEventDataFormatter eventDataFormatter; private readonly IEventDataFormatter eventDataFormatter;
private readonly IGrainFactory grainFactory; private readonly IGrainFactory grainFactory;
private readonly IAppCleanerGrain appCleaner;
private readonly ISemanticLog log; private readonly ISemanticLog log;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
private readonly IBackupArchiveLocation backupArchiveLocation; private readonly IBackupArchiveLocation backupArchiveLocation;
@ -75,8 +74,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
this.handlers = handlers; this.handlers = handlers;
this.store = store; this.store = store;
this.log = log; this.log = log;
appCleaner = grainFactory.GetGrain<IAppCleanerGrain>(SingleGrain.Id);
} }
public override async Task OnActivateAsync(string key) public override async Task OnActivateAsync(string key)
@ -244,8 +241,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
await Safe.CleanupRestoreAsync(handler, CurrentJob.AppId, CurrentJob.Id, log); await Safe.CleanupRestoreAsync(handler, CurrentJob.AppId, CurrentJob.Id, log);
} }
await appCleaner.EnqueueAppAsync(CurrentJob.AppId);
} }
} }
@ -274,8 +269,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
if (@event.Payload is AppCreated appCreated) if (@event.Payload is AppCreated appCreated)
{ {
CurrentJob.AppId = appCreated.AppId.Id; CurrentJob.AppId = appCreated.AppId.Id;
await CheckCleanupStatus();
} }
else if (@event.Payload is AppContributorAssigned appContributorAssigned) else if (@event.Payload is AppContributorAssigned appContributorAssigned)
{ {
@ -302,23 +295,6 @@ namespace Squidex.Domain.Apps.Entities.Backup
Log("Reading events completed."); Log("Reading events completed.");
} }
private async Task CheckCleanupStatus()
{
var cleaner = grainFactory.GetGrain<IAppCleanerGrain>(SingleGrain.Id);
var status = await cleaner.GetStatusAsync(CurrentJob.AppId);
if (status == CleanerStatus.Cleaning)
{
throw new BackupRestoreException("The app is removed in the background.");
}
if (status == CleanerStatus.Cleaning)
{
throw new BackupRestoreException("The app could not be cleaned.");
}
}
private void Log(string message, bool replace = false) private void Log(string message, bool replace = false)
{ {
if (replace && CurrentJob.Log.Count > 0) if (replace && CurrentJob.Log.Count > 0)

5
src/Squidex.Domain.Apps.Entities/Contents/BackupContents.cs

@ -34,11 +34,6 @@ namespace Squidex.Domain.Apps.Entities.Contents
this.contentRepository = contentRepository; this.contentRepository = contentRepository;
} }
public override Task RemoveAsync(Guid appId)
{
return contentRepository.RemoveAsync(appId);
}
public override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader) public override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader)
{ {
switch (@event.Payload) switch (@event.Payload)

34
src/Squidex.Domain.Apps.Entities/History/BackupHistory.cs

@ -1,34 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Domain.Apps.Entities.History.Repositories;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.History
{
public sealed class BackupHistory : BackupHandler
{
private readonly IHistoryEventRepository historyEventRepository;
public override string Name { get; } = "History";
public BackupHistory(IHistoryEventRepository historyEventRepository)
{
Guard.NotNull(historyEventRepository, nameof(historyEventRepository));
this.historyEventRepository = historyEventRepository;
}
public override Task RemoveAsync(Guid appId)
{
return historyEventRepository.RemoveAsync(appId);
}
}
}

14
src/Squidex.Domain.Apps.Entities/Rules/BackupRules.cs

@ -40,20 +40,6 @@ namespace Squidex.Domain.Apps.Entities.Rules
this.ruleEventRepository = ruleEventRepository; this.ruleEventRepository = ruleEventRepository;
} }
public override async Task RemoveAsync(Guid appId)
{
await grainFactory.GetGrain<IRulesByAppIndex>(appId).ClearAsync();
var idsToRemove = await grainFactory.GetGrain<IRulesByAppIndex>(appId).GetRuleIdsAsync();
foreach (var ruleId in idsToRemove)
{
await RemoveSnapshotAsync<RuleState>(ruleId);
}
await ruleEventRepository.RemoveAsync(appId);
}
public override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader) public override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader)
{ {
switch (@event.Payload) switch (@event.Payload)

14
src/Squidex.Domain.Apps.Entities/Schemas/BackupSchemas.cs

@ -42,20 +42,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas
this.grainFactory = grainFactory; this.grainFactory = grainFactory;
} }
public override async Task RemoveAsync(Guid appId)
{
var index = grainFactory.GetGrain<ISchemasByAppIndex>(appId);
var idsToRemove = await index.GetSchemaIdsAsync();
foreach (var schemaId in idsToRemove)
{
await RemoveSnapshotAsync<SchemaState>(schemaId);
}
await index.ClearAsync();
}
public override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader) public override Task RestoreEventAsync(Envelope<IEvent> @event, Guid appId, BackupReader reader)
{ {
switch (@event.Payload) switch (@event.Payload)

18
src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs

@ -23,7 +23,8 @@ namespace Squidex.Areas.Api.Controllers.Backups
[ApiAuthorize] [ApiAuthorize]
[ApiExceptionFilter] [ApiExceptionFilter]
[ApiModelValidation(true)] [ApiModelValidation(true)]
[SwaggerTag(nameof(Backups))] [MustBeAdministrator]
[SwaggerIgnore]
public class RestoreController : ApiController public class RestoreController : ApiController
{ {
private readonly IGrainFactory grainFactory; private readonly IGrainFactory grainFactory;
@ -34,16 +35,8 @@ namespace Squidex.Areas.Api.Controllers.Backups
this.grainFactory = grainFactory; this.grainFactory = grainFactory;
} }
/// <summary>
/// Get the restore jobs.
/// </summary>
/// <returns>
/// 200 => Restore job returned.
/// 404 => App not found.
/// </returns>
[HttpGet] [HttpGet]
[Route("apps/restore/")] [Route("apps/restore/")]
[ProducesResponseType(typeof(RestoreJobDto), 200)]
[ApiCosts(0)] [ApiCosts(0)]
public async Task<IActionResult> GetJob() public async Task<IActionResult> GetJob()
{ {
@ -63,13 +56,6 @@ namespace Squidex.Areas.Api.Controllers.Backups
return Ok(response); return Ok(response);
} }
/// <summary>
/// Start a new restore job.
/// </summary>
/// <param name="request">The request object.</param>
/// <returns>
/// 204 => Backup started.
/// </returns>
[HttpPost] [HttpPost]
[Route("apps/restore/")] [Route("apps/restore/")]
[ApiCosts(0)] [ApiCosts(0)]

6
src/Squidex/Config/Domain/EntitiesServices.cs

@ -178,9 +178,6 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<CreateProfileCommandMiddleware>() services.AddSingletonAs<CreateProfileCommandMiddleware>()
.As<ICommandMiddleware>(); .As<ICommandMiddleware>();
services.AddSingletonAs<EnqueueAppToCleanerMiddleware>()
.As<ICommandMiddleware>();
} }
private static void AddBackupHandlers(this IServiceCollection services) private static void AddBackupHandlers(this IServiceCollection services)
@ -194,9 +191,6 @@ namespace Squidex.Config.Domain
services.AddTransientAs<BackupContents>() services.AddTransientAs<BackupContents>()
.As<BackupHandler>(); .As<BackupHandler>();
services.AddTransientAs<BackupHistory>()
.As<BackupHandler>();
services.AddTransientAs<BackupRules>() services.AddTransientAs<BackupRules>()
.As<BackupHandler>(); .As<BackupHandler>();

2
src/Squidex/Config/Orleans/SiloWrapper.cs

@ -15,7 +15,6 @@ using Orleans;
using Orleans.Configuration; using Orleans.Configuration;
using Orleans.Hosting; using Orleans.Hosting;
using Squidex.Config.Domain; using Squidex.Config.Domain;
using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.Rules; using Squidex.Domain.Apps.Entities.Rules;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -63,7 +62,6 @@ namespace Squidex.Config.Orleans
.EnableDirectClient() .EnableDirectClient()
.AddIncomingGrainCallFilter<LocalCacheFilter>() .AddIncomingGrainCallFilter<LocalCacheFilter>()
.AddStartupTask<Bootstrap<IContentSchedulerGrain>>() .AddStartupTask<Bootstrap<IContentSchedulerGrain>>()
.AddStartupTask<Bootstrap<IAppCleanerGrain>>()
.AddStartupTask<Bootstrap<IEventConsumerManagerGrain>>() .AddStartupTask<Bootstrap<IEventConsumerManagerGrain>>()
.AddStartupTask<Bootstrap<IRuleDequeuerGrain>>() .AddStartupTask<Bootstrap<IRuleDequeuerGrain>>()
.AddStartupTask((services, ct) => .AddStartupTask((services, ct) =>

5
src/Squidex/app/features/administration/administration-area.component.html

@ -12,6 +12,11 @@
<i class="nav-icon icon-user-o"></i> <div class="nav-text">Users</div> <i class="nav-icon icon-user-o"></i> <div class="nav-text">Users</div>
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link" routerLink="restore" routerLinkActive="active">
<i class="nav-icon icon-backup"></i> <div class="nav-text">Restore</div>
</a>
</li>
</ul> </ul>
</div> </div>

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

@ -11,6 +11,7 @@ export * from './guards/user-must-exist.guard';
export * from './guards/unset-user.guard'; export * from './guards/unset-user.guard';
export * from './pages/event-consumers/event-consumers-page.component'; export * from './pages/event-consumers/event-consumers-page.component';
export * from './pages/restore/restore-page.component';
export * from './pages/users/user-page.component'; export * from './pages/users/user-page.component';
export * from './pages/users/users-page.component'; export * from './pages/users/users-page.component';

6
src/Squidex/app/features/administration/module.ts

@ -18,6 +18,7 @@ import {
EventConsumersPageComponent, EventConsumersPageComponent,
EventConsumersService, EventConsumersService,
EventConsumersState, EventConsumersState,
RestorePageComponent,
UnsetUserGuard, UnsetUserGuard,
UserMustExistGuard, UserMustExistGuard,
UserPageComponent, UserPageComponent,
@ -38,6 +39,10 @@ const routes: Routes = [
path: 'event-consumers', path: 'event-consumers',
component: EventConsumersPageComponent component: EventConsumersPageComponent
}, },
{
path: 'restore',
component: RestorePageComponent
},
{ {
path: 'users', path: 'users',
component: UsersPageComponent, component: UsersPageComponent,
@ -69,6 +74,7 @@ const routes: Routes = [
declarations: [ declarations: [
AdministrationAreaComponent, AdministrationAreaComponent,
EventConsumersPageComponent, EventConsumersPageComponent,
RestorePageComponent,
UserPageComponent, UserPageComponent,
UsersPageComponent UsersPageComponent
], ],

65
src/Squidex/app/features/administration/pages/restore/restore-page.component.html

@ -0,0 +1,65 @@
<sqx-title message="Restore Backup"></sqx-title>
<sqx-panel theme="light" desiredWidth="70rem">
<ng-container title>
Restore Backup
</ng-container>
<ng-container content>
<ng-container *ngIf="restoreJob; let job">
<div class="card section">
<div class="card-header">
<div class="row no-gutters">
<div class="col col-auto pr-2">
<div *ngIf="job.status === 'Started'" class="restore-status restore-status-pending spin">
<i class="icon-hour-glass"></i>
</div>
<div *ngIf="job.status === 'Failed'" class="restore-status restore-status-failed">
<i class="icon-exclamation"></i>
</div>
<div *ngIf="job.status === 'Completed'" class="restore-status restore-status-success">
<i class="icon-checkmark"></i>
</div>
</div>
<div class="col">
<h3>Last Restore Operation</h3>
</div>
<div class="col text-right restore-url">
{{job.url}}
</div>
</div>
</div>
<div class="card-body">
<div *ngFor="let row of job.log">
{{row}}
</div>
</div>
<div class="card-footer text-muted">
<div class="row">
<div class="col">
Started: {{job.started | sqxISODate}}
</div>
<div class="col text-right" *ngIf="job.stopped">
Stopped: {{job.stopped | sqxISODate}}
</div>
</div>
</div>
</div>
</ng-container>
<div class="table-items-row">
<form [formGroup]="restoreForm.form" (submit)="restore()">
<div class="row no-gutters">
<div class="col">
<input class="form-control" name="url" formControlName="url" placeholder="Url to backup" />
</div>
<div class="col col-auto pl-1">
<button type="submit" class="btn btn-success" [disabled]="restoreForm.hasNoUrl | async">Restore Backup</button>
</div>
</div>
</form>
</div>
</ng-container>
</sqx-panel>

1
src/Squidex/app/features/apps/pages/restore-page.component.scss → src/Squidex/app/features/administration/pages/restore/restore-page.component.scss

@ -62,6 +62,7 @@ h3 {
} }
&-url { &-url {
@include truncate;
line-height: 30px; line-height: 30px;
} }
} }

0
src/Squidex/app/features/apps/pages/restore-page.component.ts → src/Squidex/app/features/administration/pages/restore/restore-page.component.ts

3
src/Squidex/app/features/apps/declarations.ts

@ -6,5 +6,4 @@
*/ */
export * from './pages/apps-page.component'; export * from './pages/apps-page.component';
export * from './pages/onboarding-dialog.component'; export * from './pages/onboarding-dialog.component';
export * from './pages/restore-page.component';

9
src/Squidex/app/features/apps/module.ts

@ -12,17 +12,13 @@ import { SqxFrameworkModule, SqxSharedModule } from '@app/shared';
import { import {
AppsPageComponent, AppsPageComponent,
OnboardingDialogComponent, OnboardingDialogComponent
RestorePageComponent
} from './declarations'; } from './declarations';
const routes: Routes = [ const routes: Routes = [
{ {
path: '', path: '',
component: AppsPageComponent component: AppsPageComponent
}, {
path: 'restore',
component: RestorePageComponent
} }
]; ];
@ -34,8 +30,7 @@ const routes: Routes = [
], ],
declarations: [ declarations: [
AppsPageComponent, AppsPageComponent,
OnboardingDialogComponent, OnboardingDialogComponent
RestorePageComponent
] ]
}) })
export class SqxFeatureAppsModule { } export class SqxFeatureAppsModule { }

4
src/Squidex/app/features/apps/pages/apps-page.component.html

@ -76,10 +76,6 @@
</div> </div>
</div> </div>
<div class="apps-section">
<a class="restore-link" [routerLink]="['/app/restore']">Restore app from backup</a>
</div>
<ng-container *sqxModalView="addAppDialog;onRoot:true"> <ng-container *sqxModalView="addAppDialog;onRoot:true">
<sqx-app-form [template]="addAppTemplate" <sqx-app-form [template]="addAppTemplate"
(completed)="addAppDialog.hide()"> (completed)="addAppDialog.hide()">

4
src/Squidex/app/features/apps/pages/apps-page.component.scss

@ -17,10 +17,6 @@
} }
} }
.restore-link {
font-size: 0.8rem;
}
.card { .card {
& { & {
margin-right: 1rem; margin-right: 1rem;

59
src/Squidex/app/features/apps/pages/restore-page.component.html

@ -1,59 +0,0 @@
<sqx-title message="Restore Backup"></sqx-title>
<div class="container">
<ng-container *ngIf="restoreJob; let job">
<div class="card section">
<div class="card-header">
<div class="row no-gutters">
<div class="col col-auto pr-2">
<div *ngIf="job.status === 'Started'" class="restore-status restore-status-pending spin">
<i class="icon-hour-glass"></i>
</div>
<div *ngIf="job.status === 'Failed'" class="restore-status restore-status-failed">
<i class="icon-exclamation"></i>
</div>
<div *ngIf="job.status === 'Completed'" class="restore-status restore-status-success">
<i class="icon-checkmark"></i>
</div>
</div>
<div class="col">
<h3>Last Restore Operation</h3>
</div>
<div class="col text-right restore-url">
{{job.url}}
</div>
</div>
</div>
<div class="card-body">
<div *ngFor="let row of job.log">
{{row}}
</div>
</div>
<div class="card-footer text-muted">
<div class="row">
<div class="col">
Started: {{job.started | sqxISODate}}
</div>
<div class="col text-right" *ngIf="job.stopped">
Stopped: {{job.stopped | sqxISODate}}
</div>
</div>
</div>
</div>
</ng-container>
<div class="table-items-row">
<form [formGroup]="restoreForm.form" (submit)="restore()">
<div class="row no-gutters">
<div class="col">
<input class="form-control" name="url" formControlName="url" placeholder="Url to backup" />
</div>
<div class="col col-auto pl-1">
<button type="submit" class="btn btn-success" [disabled]="restoreForm.hasNoUrl | async">Restore Backup</button>
</div>
</div>
</form>
</div>
</div>

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

@ -9,10 +9,26 @@
<link rel="stylesheet" href="style.css"></head> <link rel="stylesheet" href="style.css"></head>
<body> <body>
<div class="bgc1 clearfix"> <div class="bgc1 clearfix">
<h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;94)</small></h1> <h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;95)</small></h1>
</div> </div>
<div class="clearfix mhl ptl"> <div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 24</h1> <h1 class="mvm mtn fgc1">Grid Size: 24</h1>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-backup">
</span>
<span class="mls"> icon-backup</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e95b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe95b;" 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 fs1"> <div class="glyph fs1">
<div class="clearfix bshadow0 pbs"> <div class="clearfix bshadow0 pbs">
<span class="icon-support"> <span class="icon-support">

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

Binary file not shown.

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

@ -98,6 +98,7 @@
<glyph unicode="&#xe958;" glyph-name="single-content" horiz-adv-x="1029" d="M251.429 850.277c-87.896 0-160-72.104-160-160v-525.714c0-87.896 72.104-160 160-160h525.714c87.896 0 160 72.104 160 160v525.714c0 87.896-72.104 160-160 160zM251.429 804.562h525.714c62.961 0 114.286-51.325 114.286-114.286v-525.714c0-62.961-51.325-114.286-114.286-114.286h-525.714c-62.961 0-114.286 51.325-114.286 114.286v525.714c0 62.961 51.325 114.286 114.286 114.286zM251.429 644.562c-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.002h525.697c0.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.002h0.017zM251.429 507.419c-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.002h297.126c0.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.002h0.017zM251.429 370.277c-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.002h297.126c0.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.002h0.017z" /> <glyph unicode="&#xe958;" glyph-name="single-content" horiz-adv-x="1029" d="M251.429 850.277c-87.896 0-160-72.104-160-160v-525.714c0-87.896 72.104-160 160-160h525.714c87.896 0 160 72.104 160 160v525.714c0 87.896-72.104 160-160 160zM251.429 804.562h525.714c62.961 0 114.286-51.325 114.286-114.286v-525.714c0-62.961-51.325-114.286-114.286-114.286h-525.714c-62.961 0-114.286 51.325-114.286 114.286v525.714c0 62.961 51.325 114.286 114.286 114.286zM251.429 644.562c-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.002h525.697c0.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.002h0.017zM251.429 507.419c-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.002h297.126c0.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.002h0.017zM251.429 370.277c-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.002h297.126c0.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.002h0.017z" />
<glyph unicode="&#xe959;" glyph-name="action-Medium" d="M121.429 688.64c1.28 12.587-3.541 25.003-12.928 33.451l-95.573 115.2v17.195h296.832l229.461-503.253 201.728 503.253h283.051v-17.195l-81.792-78.379c-7.040-5.376-10.539-14.208-9.088-22.955v-576c-1.451-8.704 2.048-17.493 9.088-22.912l79.787-78.379v-17.195h-401.493v17.195l82.645 80.299c8.107 8.107 8.107 10.496 8.107 22.955v465.536l-229.973-584.021h-31.019l-267.733 584.021v-391.424c-2.219-16.469 3.243-33.024 14.805-44.928l107.52-130.56v-17.152h-304.853v17.195l107.52 130.56c11.52 11.861 16.64 28.587 13.909 44.885v452.608z" /> <glyph unicode="&#xe959;" glyph-name="action-Medium" d="M121.429 688.64c1.28 12.587-3.541 25.003-12.928 33.451l-95.573 115.2v17.195h296.832l229.461-503.253 201.728 503.253h283.051v-17.195l-81.792-78.379c-7.040-5.376-10.539-14.208-9.088-22.955v-576c-1.451-8.704 2.048-17.493 9.088-22.912l79.787-78.379v-17.195h-401.493v17.195l82.645 80.299c8.107 8.107 8.107 10.496 8.107 22.955v465.536l-229.973-584.021h-31.019l-267.733 584.021v-391.424c-2.219-16.469 3.243-33.024 14.805-44.928l107.52-130.56v-17.152h-304.853v17.195l107.52 130.56c11.52 11.861 16.64 28.587 13.909 44.885v452.608z" />
<glyph unicode="&#xe95a;" glyph-name="support" d="M726 426.667c0-24-20-42-44-42h-426l-170-172v598c0 24 18 42 42 42h554c24 0 44-18 44-42v-384zM896 682.667c24 0 42-18 42-42v-640l-170 170h-470c-24 0-42 18-42 42v86h554v384h86z" /> <glyph unicode="&#xe95a;" glyph-name="support" d="M726 426.667c0-24-20-42-44-42h-426l-170-172v598c0 24 18 42 42 42h554c24 0 44-18 44-42v-384zM896 682.667c24 0 42-18 42-42v-640l-170 170h-470c-24 0-42 18-42 42v86h554v384h86z" />
<glyph unicode="&#xe95b;" glyph-name="backup" d="M512 810.667c212 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 426.667c0-46-40-86-86-86s-86 40-86 86 40 86 86 86 86-40 86-86z" />
<glyph unicode="&#xe9ca;" glyph-name="earth" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512-0.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.26v96c0 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-32v-192c0-12.122 6.848-23.202 17.69-28.622l110.31-55.156v-187.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.628v77.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" /> <glyph unicode="&#xe9ca;" glyph-name="earth" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512-0.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.26v96c0 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-32v-192c0-12.122 6.848-23.202 17.69-28.622l110.31-55.156v-187.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.628v77.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" />
<glyph unicode="&#xf00a;" glyph-name="grid" d="M292.571 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857z" /> <glyph unicode="&#xf00a;" glyph-name="grid" d="M292.571 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857z" />
<glyph unicode="&#xf0c9;" glyph-name="list" horiz-adv-x="878" d="M877.714 182.857v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 475.428v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 768v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571z" /> <glyph unicode="&#xf0c9;" glyph-name="list" horiz-adv-x="878" d="M877.714 182.857v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 475.428v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 768v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571z" />

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 79 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.

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

@ -1,6 +1,35 @@
{ {
"IcoMoonType": "selection", "IcoMoonType": "selection",
"icons": [ "icons": [
{
"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": 2,
"prevSize": 24,
"code": 59739,
"name": "backup"
},
"setIdx": 1,
"setId": 3,
"iconIdx": 0
},
{ {
"icon": { "icon": {
"paths": [ "paths": [
@ -26,9 +55,9 @@
"code": 59738, "code": 59738,
"name": "support" "name": "support"
}, },
"setIdx": 0, "setIdx": 1,
"setId": 3, "setId": 3,
"iconIdx": 0 "iconIdx": 2
}, },
{ {
"icon": { "icon": {
@ -55,7 +84,7 @@
"code": 59705, "code": 59705,
"name": "control-RichText" "name": "control-RichText"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 90 "iconIdx": 90
}, },
@ -84,7 +113,7 @@
"code": 59710, "code": 59710,
"name": "download" "name": "download"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 91 "iconIdx": 91
}, },
@ -113,7 +142,7 @@
"code": 59737, "code": 59737,
"name": "action-Medium" "name": "action-Medium"
}, },
"setIdx": 1, "setIdx": 2,
"setId": 2, "setId": 2,
"iconIdx": 0 "iconIdx": 0
}, },
@ -142,7 +171,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59729 "code": 59729
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 44 "iconIdx": 44
}, },
@ -172,7 +201,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59726 "code": 59726
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 45 "iconIdx": 45
}, },
@ -204,7 +233,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59727 "code": 59727
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 46 "iconIdx": 46
}, },
@ -233,7 +262,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59724 "code": 59724
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 47 "iconIdx": 47
}, },
@ -271,7 +300,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59722 "code": 59722
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 48 "iconIdx": 48
}, },
@ -300,7 +329,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59652 "code": 59652
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 49 "iconIdx": 49
}, },
@ -329,7 +358,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59653 "code": 59653
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 50 "iconIdx": 50
}, },
@ -358,7 +387,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59654 "code": 59654
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 51 "iconIdx": 51
}, },
@ -387,7 +416,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59655 "code": 59655
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 52 "iconIdx": 52
}, },
@ -416,7 +445,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59656 "code": 59656
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 53 "iconIdx": 53
}, },
@ -445,7 +474,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59657 "code": 59657
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 54 "iconIdx": 54
}, },
@ -474,7 +503,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59658 "code": 59658
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 55 "iconIdx": 55
}, },
@ -503,7 +532,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59659 "code": 59659
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 56 "iconIdx": 56
}, },
@ -532,7 +561,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59660 "code": 59660
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 57 "iconIdx": 57
}, },
@ -561,7 +590,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59661 "code": 59661
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 58 "iconIdx": 58
}, },
@ -590,7 +619,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59662 "code": 59662
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 59 "iconIdx": 59
}, },
@ -619,7 +648,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59663 "code": 59663
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 60 "iconIdx": 60
}, },
@ -648,7 +677,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59664 "code": 59664
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 61 "iconIdx": 61
}, },
@ -683,7 +712,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59665 "code": 59665
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 62 "iconIdx": 62
}, },
@ -712,7 +741,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59666 "code": 59666
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 63 "iconIdx": 63
}, },
@ -741,7 +770,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59667 "code": 59667
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 64 "iconIdx": 64
}, },
@ -770,7 +799,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59668 "code": 59668
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 65 "iconIdx": 65
}, },
@ -799,7 +828,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59669 "code": 59669
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 66 "iconIdx": 66
}, },
@ -828,7 +857,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59670 "code": 59670
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 67 "iconIdx": 67
}, },
@ -857,7 +886,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59671 "code": 59671
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 68 "iconIdx": 68
}, },
@ -886,7 +915,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59672 "code": 59672
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 69 "iconIdx": 69
}, },
@ -916,7 +945,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59713 "code": 59713
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 70 "iconIdx": 70
}, },
@ -945,7 +974,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59673 "code": 59673
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 71 "iconIdx": 71
}, },
@ -974,7 +1003,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59675 "code": 59675
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 72 "iconIdx": 72
}, },
@ -1003,7 +1032,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59676 "code": 59676
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 73 "iconIdx": 73
}, },
@ -1032,7 +1061,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59677 "code": 59677
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 74 "iconIdx": 74
}, },
@ -1061,7 +1090,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59678 "code": 59678
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 75 "iconIdx": 75
}, },
@ -1090,7 +1119,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59679 "code": 59679
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 76 "iconIdx": 76
}, },
@ -1119,7 +1148,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59680 "code": 59680
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 77 "iconIdx": 77
}, },
@ -1157,7 +1186,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59681 "code": 59681
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 78 "iconIdx": 78
}, },
@ -1186,7 +1215,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59682 "code": 59682
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 79 "iconIdx": 79
}, },
@ -1215,7 +1244,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59683 "code": 59683
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 80 "iconIdx": 80
}, },
@ -1244,7 +1273,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59684 "code": 59684
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 81 "iconIdx": 81
}, },
@ -1273,7 +1302,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59685 "code": 59685
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 82 "iconIdx": 82
}, },
@ -1302,7 +1331,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59674 "code": 59674
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 83 "iconIdx": 83
}, },
@ -1331,7 +1360,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59686 "code": 59686
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 84 "iconIdx": 84
}, },
@ -1360,7 +1389,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59687 "code": 59687
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 85 "iconIdx": 85
}, },
@ -1389,7 +1418,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59688 "code": 59688
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 86 "iconIdx": 86
}, },
@ -1428,7 +1457,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59736 "code": 59736
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 0 "iconIdx": 0
}, },
@ -1470,7 +1499,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59735 "code": 59735
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 1 "iconIdx": 1
}, },
@ -1508,7 +1537,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59734 "code": 59734
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 3 "iconIdx": 3
}, },
@ -1538,7 +1567,7 @@
"code": 59733, "code": 59733,
"name": "exclamation" "name": "exclamation"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 4 "iconIdx": 4
}, },
@ -1568,7 +1597,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59730 "code": 59730
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 5 "iconIdx": 5
}, },
@ -1598,7 +1627,7 @@
"code": 59725, "code": 59725,
"name": "action-Slack" "name": "action-Slack"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 6 "iconIdx": 6
}, },
@ -1627,7 +1656,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59723 "code": 59723
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 7 "iconIdx": 7
}, },
@ -1659,7 +1688,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59721 "code": 59721
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 8 "iconIdx": 8
}, },
@ -1691,7 +1720,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59711 "code": 59711
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 9 "iconIdx": 9
}, },
@ -1721,7 +1750,7 @@
"code": 59648, "code": 59648,
"name": "angle-down" "name": "angle-down"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 10 "iconIdx": 10
}, },
@ -1751,7 +1780,7 @@
"code": 59649, "code": 59649,
"name": "angle-left" "name": "angle-left"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 11 "iconIdx": 11
}, },
@ -1781,7 +1810,7 @@
"code": 59697, "code": 59697,
"name": "angle-right" "name": "angle-right"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 12 "iconIdx": 12
}, },
@ -1811,7 +1840,7 @@
"code": 59651, "code": 59651,
"name": "angle-up" "name": "angle-up"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 13 "iconIdx": 13
}, },
@ -1852,7 +1881,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59717 "code": 59717
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 14 "iconIdx": 14
}, },
@ -1887,7 +1916,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59720 "code": 59720
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 15 "iconIdx": 15
}, },
@ -1917,7 +1946,7 @@
"code": 59709, "code": 59709,
"name": "bug" "name": "bug"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 16 "iconIdx": 16
}, },
@ -1947,7 +1976,7 @@
"code": 59692, "code": 59692,
"name": "caret-down" "name": "caret-down"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 17 "iconIdx": 17
}, },
@ -1977,7 +2006,7 @@
"code": 59690, "code": 59690,
"name": "caret-left" "name": "caret-left"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 18 "iconIdx": 18
}, },
@ -2007,7 +2036,7 @@
"code": 59689, "code": 59689,
"name": "caret-right" "name": "caret-right"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 19 "iconIdx": 19
}, },
@ -2037,7 +2066,7 @@
"code": 59691, "code": 59691,
"name": "caret-up" "name": "caret-up"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 20 "iconIdx": 20
}, },
@ -2075,7 +2104,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59718 "code": 59718
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 21 "iconIdx": 21
}, },
@ -2104,7 +2133,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59702 "code": 59702
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 22 "iconIdx": 22
}, },
@ -2133,7 +2162,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59703 "code": 59703
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 23 "iconIdx": 23
}, },
@ -2162,7 +2191,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59704 "code": 59704
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 24 "iconIdx": 24
}, },
@ -2189,7 +2218,7 @@
"prevSize": 28, "prevSize": 28,
"code": 61450 "code": 61450
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 25 "iconIdx": 25
}, },
@ -2218,7 +2247,7 @@
"prevSize": 28, "prevSize": 28,
"code": 61641 "code": 61641
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 26 "iconIdx": 26
}, },
@ -2247,7 +2276,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59698 "code": 59698
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 27 "iconIdx": 27
}, },
@ -2297,7 +2326,7 @@
"prevSize": 28, "prevSize": 28,
"code": 59719 "code": 59719
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 28 "iconIdx": 28
}, },
@ -2329,7 +2358,7 @@
"code": 59732, "code": 59732,
"name": "hour-glass" "name": "hour-glass"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 29 "iconIdx": 29
}, },
@ -2362,7 +2391,7 @@
"code": 59731, "code": 59731,
"name": "spinner" "name": "spinner"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 30 "iconIdx": 30
}, },
@ -2393,7 +2422,7 @@
"code": 59728, "code": 59728,
"name": "clock" "name": "clock"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 31 "iconIdx": 31
}, },
@ -2430,7 +2459,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59650 "code": 59650
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 32 "iconIdx": 32
}, },
@ -2463,7 +2492,7 @@
"prevSize": 32, "prevSize": 32,
"code": 59850 "code": 59850
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 33 "iconIdx": 33
}, },
@ -2496,7 +2525,7 @@
"code": 59715, "code": 59715,
"name": "elapsed" "name": "elapsed"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 34 "iconIdx": 34
}, },
@ -2526,7 +2555,7 @@
"code": 59707, "code": 59707,
"name": "google" "name": "google"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 35 "iconIdx": 35
}, },
@ -2558,7 +2587,7 @@
"code": 59700, "code": 59700,
"name": "lock" "name": "lock"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 36 "iconIdx": 36
}, },
@ -2589,7 +2618,7 @@
"code": 59712, "code": 59712,
"name": "microsoft, action-AzureQueue" "name": "microsoft, action-AzureQueue"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 37 "iconIdx": 37
}, },
@ -2619,7 +2648,7 @@
"code": 59695, "code": 59695,
"name": "pause" "name": "pause"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 38 "iconIdx": 38
}, },
@ -2649,7 +2678,7 @@
"code": 59696, "code": 59696,
"name": "play" "name": "play"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 39 "iconIdx": 39
}, },
@ -2688,7 +2717,7 @@
"code": 59694, "code": 59694,
"name": "reset" "name": "reset"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 40 "iconIdx": 40
}, },
@ -2723,7 +2752,7 @@
"code": 59693, "code": 59693,
"name": "settings2" "name": "settings2"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 41 "iconIdx": 41
}, },
@ -2757,7 +2786,7 @@
"code": 59716, "code": 59716,
"name": "timeout" "name": "timeout"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 42 "iconIdx": 42
}, },
@ -2787,7 +2816,7 @@
"code": 59699, "code": 59699,
"name": "unlocked" "name": "unlocked"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 43 "iconIdx": 43
}, },
@ -2820,7 +2849,7 @@
"code": 59701, "code": 59701,
"name": "browser" "name": "browser"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 87 "iconIdx": 87
}, },
@ -2852,7 +2881,7 @@
"code": 59714, "code": 59714,
"name": "checkmark" "name": "checkmark"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 88 "iconIdx": 88
}, },
@ -2882,7 +2911,7 @@
"code": 59706, "code": 59706,
"name": "control-Stars" "name": "control-Stars"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 89 "iconIdx": 89
}, },
@ -2911,7 +2940,7 @@
"code": 59708, "code": 59708,
"name": "info" "name": "info"
}, },
"setIdx": 2, "setIdx": 3,
"setId": 1, "setId": 1,
"iconIdx": 92 "iconIdx": 92
} }

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

@ -1,10 +1,10 @@
@font-face { @font-face {
font-family: 'icomoon'; font-family: 'icomoon';
src: url('fonts/icomoon.eot?lx1t7v'); src: url('fonts/icomoon.eot?za0y3d');
src: url('fonts/icomoon.eot?lx1t7v#iefix') format('embedded-opentype'), src: url('fonts/icomoon.eot?za0y3d#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?lx1t7v') format('truetype'), url('fonts/icomoon.ttf?za0y3d') format('truetype'),
url('fonts/icomoon.woff?lx1t7v') format('woff'), url('fonts/icomoon.woff?za0y3d') format('woff'),
url('fonts/icomoon.svg?lx1t7v#icomoon') format('svg'); url('fonts/icomoon.svg?za0y3d#icomoon') format('svg');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@ -24,6 +24,9 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-backup:before {
content: "\e95b";
}
.icon-support:before { .icon-support:before {
content: "\e95a"; content: "\e95a";
} }

48
tests/Squidex.Domain.Apps.Entities.Tests/Backup/EnqueueAppToCleanerMiddlewareTests.cs

@ -1,48 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using FakeItEasy;
using Orleans;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Orleans;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Backup
{
public class EnqueueAppToCleanerMiddlewareTests
{
private readonly IGrainFactory grainFactory = A.Fake<IGrainFactory>();
private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
private readonly IAppCleanerGrain index = A.Fake<IAppCleanerGrain>();
private readonly Guid appId = Guid.NewGuid();
private readonly EnqueueAppToCleanerMiddleware sut;
public EnqueueAppToCleanerMiddlewareTests()
{
A.CallTo(() => grainFactory.GetGrain<IAppCleanerGrain>(SingleGrain.Id, null))
.Returns(index);
sut = new EnqueueAppToCleanerMiddleware(grainFactory);
}
[Fact]
public async Task Should_enqueue_for_cleanup_on_archive()
{
var context =
new CommandContext(new ArchiveApp { AppId = appId }, commandBus)
.Complete();
await sut.HandleAsync(context);
A.CallTo(() => index.EnqueueAppAsync(appId))
.MustHaveHappened();
}
}
}
Loading…
Cancel
Save