Browse Source

Backup tests.

pull/261/head
Sebastian Stehle 9 years ago
parent
commit
c47f999749
  1. 55
      src/Squidex/Areas/Api/Controllers/Backups/BackupsContentController.cs
  2. 31
      src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs
  3. 19
      src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs
  4. 70
      src/Squidex/app/features/settings/pages/backups/backups-page.component.html
  5. 28
      src/Squidex/app/features/settings/pages/backups/backups-page.component.scss
  6. 52
      src/Squidex/app/features/settings/pages/backups/backups-page.component.ts
  7. 101
      src/Squidex/app/shared/services/backups.service.spec.ts
  8. 14
      src/Squidex/app/shared/services/backups.service.ts
  9. 29
      src/Squidex/app/theme/_common.scss
  10. 15
      src/Squidex/app/theme/_mixins.scss
  11. 2
      src/Squidex/app/theme/icomoon/demo-files/demo.css
  12. 828
      src/Squidex/app/theme/icomoon/demo.html
  13. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.eot
  14. 3
      src/Squidex/app/theme/icomoon/fonts/icomoon.svg
  15. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.ttf
  16. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.woff
  17. 1473
      src/Squidex/app/theme/icomoon/selection.json
  18. 136
      src/Squidex/app/theme/icomoon/style.css

55
src/Squidex/Areas/Api/Controllers/Backups/BackupsContentController.cs

@ -0,0 +1,55 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Commands;
using Squidex.Pipeline;
namespace Squidex.Areas.Api.Controllers.Backups
{
/// <summary>
/// Manages backups for app.
/// </summary>
[ApiAuthorize]
[ApiExceptionFilter]
[AppApi]
[SwaggerTag(nameof(Backups))]
public class BackupsContentController : ApiController
{
private readonly IAssetStore assetStore;
public BackupsContentController(ICommandBus commandBus, IAssetStore assetStore)
: base(commandBus)
{
this.assetStore = assetStore;
}
/// <summary>
/// Get the backup content.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the asset.</param>
/// <returns>
/// 200 => Backup found and content returned.
/// 404 => Backup or app not found.
/// </returns>
[HttpGet]
[Route("apps/{app}/backups/{id}")]
[ProducesResponseType(200)]
[ApiCosts(0)]
public IActionResult GetBackupContent(string app, Guid id)
{
return new FileCallbackResult("application/zip", "Backup.zip", bodyStream =>
{
return assetStore.DownloadAsync(id.ToString(), 0, null, bodyStream);
});
}
}
}

31
src/Squidex/Areas/Api/Controllers/Backup/BackupController.cs → src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs

@ -12,15 +12,14 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using Orleans;
using Squidex.Areas.Api.Controllers.Backup.Models;
using Squidex.Areas.Api.Controllers.Backups.Models;
using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Tasks;
using Squidex.Pipeline;
namespace Squidex.Areas.Api.Controllers.Backup
namespace Squidex.Areas.Api.Controllers.Backups
{
/// <summary>
/// Manages backups for app.
@ -29,17 +28,15 @@ namespace Squidex.Areas.Api.Controllers.Backup
[ApiExceptionFilter]
[AppApi]
[MustBeAppOwner]
[SwaggerTag(nameof(Backup))]
public class BackupController : ApiController
[SwaggerTag(nameof(Backups))]
public class BackupsController : ApiController
{
private readonly IGrainFactory grainFactory;
private readonly IAssetStore assetStore;
public BackupController(ICommandBus commandBus, IGrainFactory grainFactory, IAssetStore assetStore)
public BackupsController(ICommandBus commandBus, IGrainFactory grainFactory)
: base(commandBus)
{
this.grainFactory = grainFactory;
this.assetStore = assetStore;
}
/// <summary>
@ -84,24 +81,6 @@ namespace Squidex.Areas.Api.Controllers.Backup
return NoContent();
}
/// <summary>
/// Get the backup content.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the asset.</param>
/// <returns>
/// 200 => Backup found and content returned.
/// 404 => Backup or app not found.
/// </returns>
[HttpGet]
[Route("apps/{app}/backups/{id}")]
[ProducesResponseType(200)]
[ApiCosts(0.5)]
public IActionResult GetBackupContent(string app, Guid id)
{
return new FileCallbackResult("application/zip", "Backup.zip", bodyStream => assetStore.DownloadAsync(id.ToString(), 0, null, bodyStream));
}
/// <summary>
/// Delete a backup.
/// </summary>

19
src/Squidex/Areas/Api/Controllers/Backup/Models/BackupJobDto.cs → src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobDto.cs

@ -6,33 +6,40 @@
// ==========================================================================
using System;
using System.ComponentModel.DataAnnotations;
using NodaTime;
namespace Squidex.Areas.Api.Controllers.Backup.Models
namespace Squidex.Areas.Api.Controllers.Backups.Models
{
public sealed class BackupJobDto
{
/// <summary>
/// The id of the backup job.
/// </summary>
[Required]
public Guid Id { get; set; }
/// <summary>
/// The time when the job has been started.
/// </summary>
[Required]
public Instant Started { get; set; }
/// <summary>
/// The time when the job has been stopped.
/// </summary>
public Instant? Stopped { get; }
public Instant? Stopped { get; set; }
/// <summary>
/// The number of handled events.
/// </summary>
public int HandledEvents { get; set; }
/// <summary>
/// The number of handled assets.
/// </summary>
public int HandledAssets { get; set; }
/// <summary>
/// Indicates if the job has failed.
/// </summary>
public bool Failed { get; }
public bool IsFailed { get; set; }
}
}

70
src/Squidex/app/features/settings/pages/backups/backups-page.component.html

@ -1,10 +1,10 @@
<sqx-title message="{app} | Backups | Settings" parameter1="app" [value1]="ctx.appName"></sqx-title>
<sqx-panel desiredWidth="50rem">
<sqx-panel desiredWidth="60rem">
<div class="panel-header">
<div class="panel-title-row">
<div class="float-right">
<button class="btn btn-success" (click)="startBackup()">
<button class="btn btn-success" [disabled]="backups.length === 0" (click)="startBackup()">
Start Backup
</button>
</div>
@ -19,16 +19,62 @@
<div class="panel-main">
<div class="panel-content">
<table class="table table-items table-fixed">
<tbody>
<ng-template ngFor let-backup [ngForOf]="backups | async">
<tr>
<td>{{backup.started | sqxFullDateTime }}</td>
</tr>
<tr class="spacer"></tr>
</ng-template>
</tbody>
</table>
<div class="panel-alert panel-alert-danger" *ngIf="backups.length >= 10">
Your have reached the maximum number of backups: 10.
</div>
<div class="table-items-row" *ngFor="let backup of backups">
<div class="row">
<div class="col col-auto">
<div *ngIf="!backup.stopped" class="backup-status backup-status-pending icon-spin">
<i class="icon-hour-glass"></i>
</div>
<div *ngIf="backup.stopped && backup.isFailed" class="backup-status backup-status-failed">
<i class="icon-exclamation"></i>
</div>
<div *ngIf="backup.stopped && !backup.isFailed" class="backup-status backup-status-success">
<i class="icon-checkmark"></i>
</div>
</div>
<div class="col col-auto">
<div>Started:</div>
<div>Stopped:</div>
</div>
<div class="col">
<div>
{{backup.started.toISOString()}}
</div>
<div *ngIf="backup.stopped">
{{backup.stopped.toISOString()}}
</div>
</div>
<div class="col col-auto">
<div>Progress:</div>
<div>Download:</div>
</div>
<div class="col">
<div>
<span title="Archived events">
<strong>{{backup.handledEvents}}</strong> <i class="icon-time"></i>
</span>,
<span title="Archived assets">
<strong>{{backup.handledAssets}}</strong> <i class="icon-media"></i>
</span>
</div>
<div>
<a *ngIf="backup.stopped && !backup.isFailed" href="{{getDownloadUrl(backup)}}" target="_blank">
Ready
</a>
</div>
</div>
<div class="col col-auto">
<button type="button" class="btn btn-link btn-danger" (sqxConfirmClick)="deleteBackup(backup)" confirmTitle="Delete backup"
confirmText="Do you really want to delete the backup?">
<i class="icon-bin2"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</sqx-panel>

28
src/Squidex/app/features/settings/pages/backups/backups-page.component.scss

@ -1,2 +1,28 @@
@import '_vars';
@import '_mixins';
@import '_mixins';
$cicle-size: 2.8rem;
.backup-status {
& {
@include circle($cicle-size);
line-height: $cicle-size;
text-align: center;
font-size: .4 * $cicle-size;
font-weight: normal;
background: $color-border;
color: $color-dark-foreground;
}
&-pending {
color: inherit;
}
&-failed {
background: $color-theme-error;
}
&-success {
background: $color-theme-green;
}
}

52
src/Squidex/app/features/settings/pages/backups/backups-page.component.ts

@ -5,10 +5,17 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import { AppContext, BackupsService } from 'shared';
import {
ApiUrlConfig,
AppContext,
BackupDto,
BackupsService,
DateTime,
ImmutableArray
} from 'shared';
@Component({
selector: 'sqx-backups-page',
@ -18,32 +25,57 @@ import { AppContext, BackupsService } from 'shared';
AppContext
]
})
export class BackupsPageComponent {
public backups =
Observable.timer(0, 5000)
.switchMap(t => this.backupsService.getBackups(this.ctx.appName));
export class BackupsPageComponent implements OnInit, OnDestroy {
private loadSubscription: Subscription;
constructor(public readonly ctx: AppContext,
public backups = ImmutableArray.empty<BackupDto>();
constructor(
public readonly ctx: AppContext,
private readonly apiUrl: ApiUrlConfig,
private readonly backupsService: BackupsService
) {
}
public ngOnDestroy() {
this.loadSubscription.unsubscribe();
}
public ngOnInit() {
this.loadSubscription =
Observable.timer(0, 5000)
.switchMap(t => this.backupsService.getBackups(this.ctx.appName))
.subscribe(dtos => {
this.backups = ImmutableArray.of(dtos);
});
}
public startBackup() {
this.backupsService.postBackup(this.ctx.appName)
.subscribe(() => {
const backup = new BackupDto('', DateTime.now(), null, 0, 0, false);
this.backups = this.backups.pushFront(backup);
this.ctx.notifyInfo('Backup started.');
}, error => {
this.ctx.notifyError(error);
});
}
public deleteBackup(id: string) {
this.backupsService.deleteBackup(this.ctx.appName, id)
public deleteBackup(backup: BackupDto) {
this.backupsService.deleteBackup(this.ctx.appName, backup.id)
.subscribe(() => {
this.backups = this.backups.filter(x => x.id !== backup.id);
this.ctx.notifyInfo('Backup deleting.');
}, error => {
this.ctx.notifyError(error);
});
}
public getDownloadUrl(backup: BackupDto) {
return this.apiUrl.buildUrl(`api/apps/${this.ctx.appName}/backups/${backup.id}`);
}
}

101
src/Squidex/app/shared/services/backups.service.spec.ts

@ -0,0 +1,101 @@
/*
* 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,
BackupDto,
BackupsService,
DateTime
} from './../';
describe('BackupsService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
BackupsService,
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') },
{ provide: AnalyticsService, useValue: new AnalyticsService() }
]
});
});
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
httpMock.verify();
}));
it('should make get request to get backups',
inject([BackupsService, HttpTestingController], (backupsService: BackupsService, httpMock: HttpTestingController) => {
let backups: BackupDto[] | null = null;
backupsService.getBackups('my-app').subscribe(result => {
backups = result;
});
const req = httpMock.expectOne('http://service/p/api/apps/my-app/backups');
expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush([
{
id: '1',
started: '2017-02-03',
stopped: '2017-02-04',
handledEvents: 13,
handledAssets: 17,
isFailed: false
},
{
id: '2',
started: '2018-02-03',
stopped: null,
handledEvents: 23,
handledAssets: 27,
isFailed: true
}
]);
expect(backups).toEqual([
new BackupDto('1', DateTime.parseISO_UTC('2017-02-03'), DateTime.parseISO_UTC('2017-02-04'), 13, 17, false),
new BackupDto('2', DateTime.parseISO_UTC('2018-02-03'), null, 23, 27, true)
]);
}));
it('should make post request to start backup',
inject([BackupsService, HttpTestingController], (backupsService: BackupsService, httpMock: HttpTestingController) => {
backupsService.postBackup('my-app').subscribe();
const req = httpMock.expectOne('http://service/p/api/apps/my-app/backups');
expect(req.request.method).toEqual('POST');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush({});
}));
it('should make delete request to remove language',
inject([BackupsService, HttpTestingController], (backupsService: BackupsService, httpMock: HttpTestingController) => {
backupsService.deleteBackup('my-app', '1').subscribe();
const req = httpMock.expectOne('http://service/p/api/apps/my-app/backups/1');
expect(req.request.method).toEqual('DELETE');
expect(req.request.headers.get('If-Match')).toBeNull();
req.flush({});
}));
});

14
src/Squidex/app/shared/services/backups.service.ts

@ -20,9 +20,11 @@ import {
export class BackupDto {
constructor(
public readonly id: string,
public readonly isFailed: string,
public readonly started: DateTime,
public readonly stopped: DateTime | null
public readonly stopped: DateTime | null,
public readonly handledEvents: number,
public readonly handledAssets: number,
public readonly isFailed: boolean
) {
}
}
@ -46,9 +48,11 @@ export class BackupsService {
return items.map(item => {
return new BackupDto(
item.id,
item.isFailed,
DateTime.parseISO_UTC(item.stopped),
item.stopped ? DateTime.parseISO_UTC(item.stopped) : null);
DateTime.parseISO_UTC(item.started),
item.stopped ? DateTime.parseISO_UTC(item.stopped) : null,
item.handledEvents,
item.handledAssets,
item.isFailed);
});
})
.pretifyError('Failed to load backups.');

29
src/Squidex/app/theme/_common.scss

@ -158,3 +158,32 @@ body {
background: $color-dark-foreground;
}
}
//
// Animations
//
.spin {
@include animation(spin 3s infinite linear);
}
@include keyframes (spin) {
20% {
@include rotate(0deg);
}
30% {
@include rotate(180deg);
}
70% {
@include rotate(180deg);
}
80% {
@include rotate(360deg);
}
100% {
@include rotate(360deg);
}
}

15
src/Squidex/app/theme/_mixins.scss

@ -293,6 +293,21 @@
border-radius: $radius $radius 0 0;
}
@mixin keyframes($name) {
@-webkit-keyframes #{$name} {
@content;
}
@-moz-keyframes #{$name} {
@content;
}
@keyframes #{$name} {
@content;
}
@-ms-keyframes #{$name} {
@content;
}
}
@mixin animation($animation...) {
-webkit-animation: $animation;
-moz-animation: $animation;

2
src/Squidex/app/theme/icomoon/demo-files/demo.css

@ -147,7 +147,7 @@ p {
font-size: 16px;
}
.fs1 {
font-size: 32px;
font-size: 28px;
}
.fs2 {
font-size: 32px;

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

File diff suppressed because it is too large

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

Binary file not shown.

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

@ -90,6 +90,9 @@
<glyph unicode="&#xe950;" glyph-name="clock" d="M658.744 210.744l-210.744 210.746v282.51h128v-229.49l173.256-173.254zM512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 64c-212.078 0-384 171.922-384 384s171.922 384 384 384c212.078 0 384-171.922 384-384s-171.922-384-384-384z" />
<glyph unicode="&#xe951;" glyph-name="circle" d="M1024 448c0-282.77-229.23-512-512-512s-512 229.23-512 512c0 282.77 229.23 512 512 512s512-229.23 512-512z" />
<glyph unicode="&#xe952;" glyph-name="action-ElasticSearch" horiz-adv-x="1071" d="M491.055 313.184h-338.784c-12.301 39.564-19.283 81.787-19.283 125.673s6.649 86.109 19.283 125.673h557.548c69.153 0 125.008-56.519 125.008-126.005 0-69.153-55.855-125.34-125.008-125.34h-218.764zM475.096 271.293h-306.868c32.582-74.473 86.442-137.974 153.6-182.192v0c66.161-43.553 145.288-69.153 230.4-69.153 145.288 0 273.288 74.14 348.426 186.514-38.566 39.896-92.758 64.831-152.603 64.831h-272.956zM748.052 606.421c59.844 0 114.036 24.935 152.603 64.831-75.138 112.374-203.138 186.514-348.758 186.514-85.112 0-164.239-25.6-230.4-69.153v0c-67.158-44.551-121.018-107.719-153.6-182.192h580.156z" />
<glyph unicode="&#xe953;" glyph-name="spinner" d="M192 448c0 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 448c0-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 761.592c91.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.156v-194.432zM233.55 605.768c44.906 79.084 122.516 137.164 214.45 155.826v194.43c-177.188-22.096-326.23-134.736-399.426-290.154l184.976-60.102zM644.556 156.672c-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" />
<glyph unicode="&#xe954;" glyph-name="hour-glass" d="M728.992 448c137.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 0c0 186.912 80.162 345.414 224 397.708v100.586c-143.838 52.29-224 210.792-224 397.706v0h704c0-186.914-80.162-345.416-224-397.706v-100.586c143.838-52.294 224-210.796 224-397.708h-704zM619.626 290.406c-71.654 40.644-75.608 93.368-75.626 125.366v64.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.366v-64.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" />
<glyph unicode="&#xe955;" glyph-name="exclamation" horiz-adv-x="366" d="M292.571 237.714v-128c0-20-16.571-36.571-36.571-36.571h-146.286c-20 0-36.571 16.571-36.571 36.571v128c0 20 16.571 36.571 36.571 36.571h146.286c20 0 36.571-16.571 36.571-36.571zM309.714 841.143l-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" />
<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="&#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: 72 KiB

After

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

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

File diff suppressed because it is too large

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

@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?asl9vj');
src: url('fonts/icomoon.eot?asl9vj#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?asl9vj') format('truetype'),
url('fonts/icomoon.woff?asl9vj') format('woff'),
url('fonts/icomoon.svg?asl9vj#icomoon') format('svg');
src: url('fonts/icomoon.eot?y97utm');
src: url('fonts/icomoon.eot?y97utm#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?y97utm') format('truetype'),
url('fonts/icomoon.woff?y97utm') format('woff'),
url('fonts/icomoon.svg?y97utm#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
@ -24,6 +24,9 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-exclamation:before {
content: "\e955";
}
.icon-action-ElasticSearch:before {
content: "\e952";
}
@ -102,6 +105,87 @@
.icon-action-Webhook:before {
content: "\e947";
}
.icon-hour-glass:before {
content: "\e954";
}
.icon-spinner:before {
content: "\e953";
}
.icon-clock:before {
content: "\e950";
}
.icon-bin2:before {
content: "\e902";
}
.icon-earth:before {
content: "\e9ca";
}
.icon-elapsed:before {
content: "\e943";
}
.icon-google:before {
content: "\e93b";
}
.icon-lock:before {
content: "\e934";
}
.icon-microsoft:before {
content: "\e940";
}
.icon-action-AzureQueue:before {
content: "\e940";
}
.icon-pause:before {
content: "\e92f";
}
.icon-play:before {
content: "\e930";
}
.icon-reset:before {
content: "\e92e";
}
.icon-settings2:before {
content: "\e92d";
}
.icon-timeout:before {
content: "\e944";
}
.icon-unlocked:before {
content: "\e933";
}
.icon-caret-up:before {
content: "\e92b";
}
.icon-contents:before {
content: "\e946";
}
.icon-trigger-ContentChanged:before {
content: "\e946";
}
.icon-control-Date:before {
content: "\e936";
}
.icon-control-DateTime:before {
content: "\e937";
}
.icon-control-Markdown:before {
content: "\e938";
}
.icon-grid:before {
content: "\f00a";
}
.icon-list:before {
content: "\f0c9";
}
.icon-user-o:before {
content: "\e932";
}
.icon-rules:before {
content: "\e947";
}
.icon-action-Webhook:before {
content: "\e947";
}
.icon-circle:before {
content: "\e951";
}
@ -262,48 +346,6 @@
.icon-user:before {
content: "\e928";
}
.icon-clock:before {
content: "\e950";
}
.icon-bin2:before {
content: "\e902";
}
.icon-earth:before {
content: "\e9ca";
}
.icon-elapsed:before {
content: "\e943";
}
.icon-google:before {
content: "\e93b";
}
.icon-lock:before {
content: "\e934";
}
.icon-microsoft:before {
content: "\e940";
}
.icon-action-AzureQueue:before {
content: "\e940";
}
.icon-pause:before {
content: "\e92f";
}
.icon-play:before {
content: "\e930";
}
.icon-reset:before {
content: "\e92e";
}
.icon-settings2:before {
content: "\e92d";
}
.icon-timeout:before {
content: "\e944";
}
.icon-unlocked:before {
content: "\e933";
}
.icon-browser:before {
content: "\e935";
}

Loading…
Cancel
Save