Browse Source

User management

pull/1/head
Sebastian 9 years ago
parent
commit
7f2b7f75d9
  1. 2
      src/Squidex.Read.MongoDb/Contents/MongoContentRepository.cs
  2. 14
      src/Squidex.Read.MongoDb/Contents/Visitors/FindExtensions.cs
  3. 2
      src/Squidex.Read.MongoDb/History/MongoHistoryEventRepository.cs
  4. 53
      src/Squidex.Read.MongoDb/Users/MongoUserRepository.cs
  5. 2
      src/Squidex.Read/Contents/Repositories/IContentRepository.cs
  6. 2
      src/Squidex.Read/History/Repositories/IHistoryEventRepository.cs
  7. 4
      src/Squidex.Read/Schemas/Repositories/ISchemaRepository.cs
  8. 8
      src/Squidex.Read/Users/Repositories/IUserRepository.cs
  9. 1
      src/Squidex/Config/Identity/IdentityServices.cs
  10. 1
      src/Squidex/Config/Identity/IdentityUsage.cs
  11. 3
      src/Squidex/Controllers/Api/EventConsumers/EventConsumersController.cs
  12. 2
      src/Squidex/Controllers/Api/History/HistoryController.cs
  13. 6
      src/Squidex/Controllers/Api/Users/Models/UserDto.cs
  14. 23
      src/Squidex/Controllers/Api/Users/Models/UsersDto.cs
  15. 90
      src/Squidex/Controllers/Api/Users/UserManagementController.cs
  16. 2
      src/Squidex/Controllers/Api/Users/UsersController.cs
  17. 25
      src/Squidex/Controllers/UI/Account/AccountController.cs
  18. 7
      src/Squidex/app/features/administration/administration-area.component.html
  19. 44
      src/Squidex/app/features/administration/administration-area.component.scss
  20. 1
      src/Squidex/app/features/administration/declarations.ts
  21. 11
      src/Squidex/app/features/administration/module.ts
  22. 16
      src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts
  23. 89
      src/Squidex/app/features/administration/pages/users/users-page.component.html
  24. 18
      src/Squidex/app/features/administration/pages/users/users-page.component.scss
  25. 135
      src/Squidex/app/features/administration/pages/users/users-page.component.ts
  26. 2
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  27. 2
      src/Squidex/app/features/content/pages/contents/content-item.component.ts
  28. 6
      src/Squidex/app/features/content/pages/contents/contents-page.component.html
  29. 19
      src/Squidex/app/features/content/pages/contents/contents-page.component.scss
  30. 3
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  31. 2
      src/Squidex/app/features/content/pages/schemas/schemas-page.component.ts
  32. 2
      src/Squidex/app/features/dashboard/pages/dashboard-page.component.ts
  33. 2
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  34. 2
      src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts
  35. 4
      src/Squidex/app/features/settings/pages/clients/client.component.html
  36. 2
      src/Squidex/app/features/settings/pages/clients/clients-page.component.ts
  37. 2
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html
  38. 15
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.scss
  39. 2
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts
  40. 5
      src/Squidex/app/features/settings/pages/languages/languages-page.component.scss
  41. 2
      src/Squidex/app/features/settings/pages/languages/languages-page.component.ts
  42. 67
      src/Squidex/app/shared/components/app-component-base.ts
  43. 77
      src/Squidex/app/shared/components/component-base.ts
  44. 4
      src/Squidex/app/shared/components/history.component.ts
  45. 4
      src/Squidex/app/shared/components/language-selector.component.scss
  46. 1
      src/Squidex/app/shared/declarations.ts
  47. 2
      src/Squidex/app/shared/module.ts
  48. 1
      src/Squidex/app/shared/services/app-clients.service.ts
  49. 1
      src/Squidex/app/shared/services/app-contributors.service.ts
  50. 3
      src/Squidex/app/shared/services/app-languages.service.ts
  51. 3
      src/Squidex/app/shared/services/history.service.ts
  52. 3
      src/Squidex/app/shared/services/languages.service.ts
  53. 12
      src/Squidex/app/shared/services/users-provider.service.spec.ts
  54. 4
      src/Squidex/app/shared/services/users-provider.service.ts
  55. 151
      src/Squidex/app/shared/services/users.service.spec.ts
  56. 71
      src/Squidex/app/shared/services/users.service.ts
  57. 2
      src/Squidex/app/shell/pages/app/app-area.component.scss
  58. 46
      src/Squidex/app/shell/pages/app/left-menu.component.scss
  59. 24
      src/Squidex/app/theme/_lists.scss
  60. 47
      src/Squidex/app/theme/_panels.scss
  61. 158
      src/Squidex/app/theme/icomoon/demo-files/demo.css
  62. 30
      src/Squidex/app/theme/icomoon/demo-files/demo.js
  63. 988
      src/Squidex/app/theme/icomoon/demo.html
  64. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.eot
  65. 5
      src/Squidex/app/theme/icomoon/fonts/icomoon.svg
  66. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.ttf
  67. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.woff
  68. 24
      src/Squidex/app/theme/icomoon/icons/user.svg
  69. 598
      src/Squidex/app/theme/icomoon/selection.json
  70. 61
      src/Squidex/app/theme/icomoon/style.css

2
src/Squidex.Read.MongoDb/Contents/MongoContentRepository.cs

@ -46,7 +46,7 @@ namespace Squidex.Read.MongoDb.Contents
this.schemaProvider = schemaProvider;
}
public async Task<List<IContentEntity>> QueryAsync(Guid schemaId, bool nonPublished, string odataQuery, HashSet<Language> languages)
public async Task<IReadOnlyList<IContentEntity>> QueryAsync(Guid schemaId, bool nonPublished, string odataQuery, HashSet<Language> languages)
{
List<IContentEntity> result = null;

14
src/Squidex.Read.MongoDb/Contents/Visitors/FindExtensions.cs

@ -8,6 +8,7 @@
using System.Collections.Generic;
using Microsoft.OData.Core.UriParser;
using MongoDB.Bson;
using MongoDB.Driver;
using Squidex.Core.Schemas;
@ -69,7 +70,18 @@ namespace Squidex.Read.MongoDb.Contents.Visitors
filters.Add(filter);
}
return Filter.And(filters);
if (filters.Count > 1)
{
return Filter.And(filters);
}
else if (filters.Count == 1)
{
return filters[0];
}
else
{
return new BsonDocument();
}
}
}
}

2
src/Squidex.Read.MongoDb/History/MongoHistoryEventRepository.cs

@ -59,7 +59,7 @@ namespace Squidex.Read.MongoDb.History
collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.Created), new CreateIndexOptions { ExpireAfter = TimeSpan.FromDays(365) }));
}
public async Task<List<IHistoryEventEntity>> QueryEventsByChannel(Guid appId, string channelPrefix, int count)
public async Task<IReadOnlyList<IHistoryEventEntity>> QueryByChannelAsync(Guid appId, string channelPrefix, int count)
{
var entities =
await Collection.Find(x => x.AppId == appId && x.Channel == channelPrefix)

53
src/Squidex.Read.MongoDb/Users/MongoUserRepository.cs

@ -6,6 +6,7 @@
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -15,6 +16,8 @@ using Squidex.Infrastructure;
using Squidex.Read.Users;
using Squidex.Read.Users.Repositories;
// ReSharper disable InvertIf
namespace Squidex.Read.MongoDb.Users
{
public sealed class MongoUserRepository : IUserRepository
@ -28,11 +31,18 @@ namespace Squidex.Read.MongoDb.Users
this.userManager = userManager;
}
public Task<List<IUserEntity>> QueryUsersByQuery(string query)
public Task<IReadOnlyList<IUserEntity>> QueryByEmailAsync(string email, int take = 10, int skip = 0)
{
var users = userManager.Users.Where(x => x.NormalizedEmail.Contains(query.ToUpper())).Take(10).ToList();
var users = QueryUsers(email).Skip(skip).Take(take).ToList();
return Task.FromResult(users.Select(x => (IUserEntity)new MongoUserEntity(x)).ToList());
return Task.FromResult<IReadOnlyList<IUserEntity>>(users.Select(x => (IUserEntity)new MongoUserEntity(x)).ToList());
}
public Task<long> CountAsync(string email = null)
{
var count = QueryUsers(email).LongCount();
return Task.FromResult(count);
}
public async Task<IUserEntity> FindUserByIdAsync(string id)
@ -42,11 +52,42 @@ namespace Squidex.Read.MongoDb.Users
return user != null ? new MongoUserEntity(user) : null;
}
public Task<long> CountAsync()
public async Task LockAsync(string id)
{
var count = userManager.Users.LongCount();
var user = await userManager.FindByIdAsync(id);
return Task.FromResult(count);
if (user == null)
{
throw new DomainObjectNotFoundException(id, typeof(IdentityUser));
}
await userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddYears(100));
}
public async Task UnlockAsync(string id)
{
var user = await userManager.FindByIdAsync(id);
if (user == null)
{
throw new DomainObjectNotFoundException(id, typeof(IdentityUser));
}
await userManager.SetLockoutEndDateAsync(user, null);
}
private IQueryable<IdentityUser> QueryUsers(string email = null)
{
var result = userManager.Users;
if (!string.IsNullOrWhiteSpace(email))
{
var upperEmail = email.ToUpperInvariant();
result = userManager.Users.Where(x => x.NormalizedEmail.Contains(upperEmail));
}
return result;
}
}
}

2
src/Squidex.Read/Contents/Repositories/IContentRepository.cs

@ -15,7 +15,7 @@ namespace Squidex.Read.Contents.Repositories
{
public interface IContentRepository
{
Task<List<IContentEntity>> QueryAsync(Guid schemaId, bool nonPublished, string odataQuery, HashSet<Language> languages);
Task<IReadOnlyList<IContentEntity>> QueryAsync(Guid schemaId, bool nonPublished, string odataQuery, HashSet<Language> languages);
Task<long> CountAsync(Guid schemaId, bool nonPublished, string odataQuery, HashSet<Language> languages);

2
src/Squidex.Read/History/Repositories/IHistoryEventRepository.cs

@ -14,6 +14,6 @@ namespace Squidex.Read.History.Repositories
{
public interface IHistoryEventRepository
{
Task<List<IHistoryEventEntity>> QueryEventsByChannel(Guid appId, string channelPrefix, int count);
Task<IReadOnlyList<IHistoryEventEntity>> QueryByChannelAsync(Guid appId, string channelPrefix, int count);
}
}

4
src/Squidex.Read/Schemas/Repositories/ISchemaRepository.cs

@ -21,10 +21,10 @@ namespace Squidex.Read.Schemas.Repositories
Task<IReadOnlyList<ISchemaEntityWithSchema>> QueryAllWithSchemaAsync(Guid appId);
Task<Guid?> FindSchemaIdAsync(Guid appId, string name);
Task<ISchemaEntityWithSchema> FindSchemaAsync(Guid appId, string name);
Task<ISchemaEntityWithSchema> FindSchemaAsync(Guid schemaId);
Task<Guid?> FindSchemaIdAsync(Guid appId, string name);
}
}

8
src/Squidex.Read/Users/Repositories/IUserRepository.cs

@ -13,10 +13,14 @@ namespace Squidex.Read.Users.Repositories
{
public interface IUserRepository
{
Task<List<IUserEntity>> QueryUsersByQuery(string query);
Task<IReadOnlyList<IUserEntity>> QueryByEmailAsync(string email = null, int take = 10, int skip = 0);
Task<IUserEntity> FindUserByIdAsync(string id);
Task<long> CountAsync();
Task LockAsync(string id);
Task UnlockAsync(string id);
Task<long> CountAsync(string email = null);
}
}

1
src/Squidex/Config/Identity/IdentityServices.cs

@ -21,7 +21,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Core.Identity;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Security;
using StackExchange.Redis;
namespace Squidex.Config.Identity

1
src/Squidex/Config/Identity/IdentityUsage.cs

@ -19,7 +19,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using Squidex.Core.Identity;
using Squidex.Infrastructure.Security;
// ReSharper disable InvertIf

3
src/Squidex/Controllers/Api/EventConsumers/EventConsumersController.cs

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using Squidex.Controllers.Api.EventConsumers.Models;
using Squidex.Core.Identity;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Reflection;
using Squidex.Pipeline;
@ -19,7 +20,7 @@ using Squidex.Pipeline;
namespace Squidex.Controllers.Api.EventConsumers
{
[ApiExceptionFilter]
[Authorize(Roles = "administrator")]
[Authorize(Roles = SquidexRoles.Administrator)]
[SwaggerIgnore]
public sealed class EventConsumersController : Controller
{

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

@ -61,7 +61,7 @@ namespace Squidex.Controllers.Api.History
return NotFound();
}
var schemas = await historyEventRepository.QueryEventsByChannel(entity.Id, channel, 100);
var schemas = await historyEventRepository.QueryByChannelAsync(entity.Id, channel, 100);
var response = schemas.Select(x => SimpleMapper.Map(x, new HistoryEventDto())).ToList();

6
src/Squidex/Controllers/Api/Users/Models/UserDto.cs

@ -35,5 +35,11 @@ namespace Squidex.Controllers.Api.Users.Models
/// </summary>
[Required]
public string DisplayName { get; set; }
/// <summary>
/// Determines if the user is locked.
/// </summary>
[Required]
public bool IsLocked { get; set; }
}
}

23
src/Squidex/Controllers/Api/Users/Models/UsersDto.cs

@ -0,0 +1,23 @@
// ==========================================================================
// UsersDto.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Controllers.Api.Users.Models
{
public class UsersDto
{
/// <summary>
/// The total number of users.
/// </summary>
public long Total { get; set; }
/// <summary>
/// The users.
/// </summary>
public UserDto[] Items { get; set; }
}
}

90
src/Squidex/Controllers/Api/Users/UserManagementController.cs

@ -0,0 +1,90 @@
// ==========================================================================
// UserManagementController.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using Squidex.Controllers.Api.Users.Models;
using Squidex.Core.Identity;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Security;
using Squidex.Pipeline;
using Squidex.Read.Users.Repositories;
namespace Squidex.Controllers.Api.Users
{
[ApiExceptionFilter]
[Authorize(Roles = SquidexRoles.Administrator)]
[SwaggerIgnore]
public class UserManagementController : Controller
{
private readonly IUserRepository userRepository;
public UserManagementController(IUserRepository userRepository)
{
this.userRepository = userRepository;
}
[HttpGet]
[Route("user-management")]
public async Task<IActionResult> GetUsers([FromQuery] string query = null, [FromQuery] int skip = 0, [FromQuery] int take = 10)
{
var taskForUsers = userRepository.QueryByEmailAsync(query, take, skip);
var taskForCount = userRepository.CountAsync(query);
await Task.WhenAll(taskForUsers, taskForCount);
var model = new UsersDto
{
Total = taskForCount.Result,
Items = taskForUsers.Result.Select(x => SimpleMapper.Map(x, new UserDto())).ToArray()
};
return Ok(model);
}
[HttpPut]
[Route("user-management/{id}/lock/")]
public async Task<IActionResult> Lock(string id)
{
if (IsSelf(id))
{
throw new ValidationException("Locking user failed.", new ValidationError("You cannot lock yourself."));
}
await userRepository.LockAsync(id);
return NoContent();
}
[HttpPut]
[Route("user-management/{id}/unlock/")]
public async Task<IActionResult> Unlock(string id)
{
if (IsSelf(id))
{
throw new ValidationException("Unlocking user failed.", new ValidationError("You cannot unlock yourself."));
}
await userRepository.UnlockAsync(id);
return NoContent();
}
private bool IsSelf(string id)
{
var subject = User.OpenIdSubject();
return string.Equals(subject, id, StringComparison.OrdinalIgnoreCase);
}
}
}

2
src/Squidex/Controllers/Api/Users/UsersController.cs

@ -48,7 +48,7 @@ namespace Squidex.Controllers.Api.Users
[ProducesResponseType(typeof(UserDto[]), 200)]
public async Task<IActionResult> GetUsers(string query)
{
var entities = await userRepository.QueryUsersByQuery(query ?? string.Empty);
var entities = await userRepository.QueryByEmailAsync(query ?? string.Empty);
var response = entities.Select(x => SimpleMapper.Map(x, new UserDto())).ToList();

25
src/Squidex/Controllers/UI/Account/AccountController.cs

@ -8,11 +8,11 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.MongoDB;
using Microsoft.AspNetCore.Mvc;
@ -22,7 +22,6 @@ using Microsoft.Extensions.Options;
using Squidex.Config;
using Squidex.Config.Identity;
using Squidex.Core.Identity;
using Squidex.Read.Users.Repositories;
// ReSharper disable InvertIf
// ReSharper disable RedundantIfElseBlock
@ -38,7 +37,6 @@ namespace Squidex.Controllers.UI.Account
private readonly UserManager<IdentityUser> userManager;
private readonly IOptions<MyIdentityOptions> identityOptions;
private readonly IOptions<MyUrlsOptions> urlOptions;
private readonly IUserRepository userRepository;
private readonly ILogger<AccountController> logger;
private readonly IIdentityServerInteractionService interactions;
@ -47,14 +45,12 @@ namespace Squidex.Controllers.UI.Account
UserManager<IdentityUser> userManager,
IOptions<MyIdentityOptions> identityOptions,
IOptions<MyUrlsOptions> urlOptions,
IUserRepository userRepository,
ILogger<AccountController> logger,
IIdentityServerInteractionService interactions)
{
this.logger = logger;
this.urlOptions = urlOptions;
this.userManager = userManager;
this.userRepository = userRepository;
this.interactions = interactions;
this.identityOptions = identityOptions;
this.signInManager = signInManager;
@ -119,8 +115,7 @@ namespace Squidex.Controllers.UI.Account
{
var providers =
signInManager.GetExternalAuthenticationSchemes()
.Select(x => new ExternalProvider(x.AuthenticationScheme, x.DisplayName))
.ToList();
.Select(x => new ExternalProvider(x.AuthenticationScheme, x.DisplayName)).ToList();
return View(new LoginVM { ExternalProviders = providers, ReturnUrl = returnUrl });
}
@ -160,7 +155,7 @@ namespace Squidex.Controllers.UI.Account
{
var user = CreateUser(externalLogin);
var isFirst = await userRepository.CountAsync() == 0;
var isFirst = userManager.Users.LongCount() == 0;
isLoggedIn =
await AddUserAsync(user) &&
@ -184,16 +179,14 @@ namespace Squidex.Controllers.UI.Account
}
}
private async Task<bool> AddLoginAsync(IdentityUser user, UserLoginInfo externalLogin)
private Task<bool> AddLoginAsync(IdentityUser user, UserLoginInfo externalLogin)
{
var result = await userManager.AddLoginAsync(user, externalLogin);
return result.Succeeded;
return MakeIdentityOperation(() => userManager.AddLoginAsync(user, externalLogin));
}
private Task<bool> AddUserAsync(IdentityUser user)
{
return MakeIdentityOperation("LoginAsync", () => userManager.CreateAsync(user));
return MakeIdentityOperation(() => userManager.CreateAsync(user));
}
private async Task<bool> LoginAsync(UserLoginInfo externalLogin)
@ -210,7 +203,7 @@ namespace Squidex.Controllers.UI.Account
return Task.FromResult(false);
}
return MakeIdentityOperation("LockAsync", () => userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddYears(100)));
return MakeIdentityOperation(() => userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddYears(100)));
}
private Task<bool> MakeAdminAsync(IdentityUser user, bool isFirst)
@ -220,7 +213,7 @@ namespace Squidex.Controllers.UI.Account
return Task.FromResult(false);
}
return MakeIdentityOperation("LockAsync", () => userManager.AddToRoleAsync(user, SquidexRoles.Administrator));
return MakeIdentityOperation(() => userManager.AddToRoleAsync(user, SquidexRoles.Administrator));
}
private static IdentityUser CreateUser(ExternalLoginInfo externalLogin)
@ -237,7 +230,7 @@ namespace Squidex.Controllers.UI.Account
return user;
}
private async Task<bool> MakeIdentityOperation(string operationName, Func<Task<IdentityResult>> action)
private async Task<bool> MakeIdentityOperation(Func<Task<IdentityResult>> action, [CallerMemberName] string operationName = null)
{
try
{

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

@ -2,7 +2,12 @@
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" routerLink="event-consumers" routerLinkActive="active">
<i class="nav-icon icon-time"></i> <div class="nav-text">Event Consumers</div>
<i class="nav-icon icon-time"></i> <div class="nav-text">Consumers</div>
</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="users" routerLinkActive="active">
<i class="nav-icon icon-user"></i> <div class="nav-text">Users</div>
</a>
</li>
</ul>

44
src/Squidex/app/features/administration/administration-area.component.scss

@ -1,46 +1,2 @@
@import '_vars';
@import '_mixins';
.sidebar {
@include fixed($size-navbar-height, auto, 0, 0);
@include box-shadow-colored(2px, 0, 0, $color-dark1-border2);
min-width: $size-sidebar-width;
max-width: $size-sidebar-width;
border-right: 1px solid $color-dark1-border1;
background: $color-dark1-background;
z-index: 100;
}
.nav {
&-icon {
font-size: 2rem;
}
&-text {
font-size: .9rem;
}
&-link {
& {
@include transition(color .3s ease);
padding: 1.25rem;
display: block;
text-align: center;
text-decoration: none;
color: $color-dark1-foreground;
}
&:hover,
&.active {
color: $color-dark1-focus-foreground;
.nav-icon {
color: $color-theme-blue;
}
}
&.active {
background: $color-dark1-active-background;
}
}
}

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

@ -6,5 +6,6 @@
*/
export * from './pages/event-consumers/event-consumers-page.component';
export * from './pages/users/users-page.component';
export * from './administration-area.component';

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

@ -15,7 +15,8 @@ import {
import {
AdministrationAreaComponent,
EventConsumersPage
EventConsumersPageComponent,
UsersPageComponent
} from './declarations';
const routes: Routes = [
@ -27,7 +28,10 @@ const routes: Routes = [
path: '',
children: [{
path: 'event-consumers',
component: EventConsumersPage
component: EventConsumersPageComponent
}, {
path: 'users',
component: UsersPageComponent
}]
}
]
@ -42,7 +46,8 @@ const routes: Routes = [
],
declarations: [
AdministrationAreaComponent,
EventConsumersPage
EventConsumersPageComponent,
UsersPageComponent
]
})
export class SqxFeatureAdministrationModule { }

16
src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts

@ -9,11 +9,14 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { Observable, Subscription } from 'rxjs';
import {
ComponentBase,
EventConsumerDto,
EventConsumersService,
fadeAnimation,
ImmutableArray,
ModalView
ModalView,
NotificationService,
UsersProviderService
} from 'shared';
@Component({
@ -24,16 +27,17 @@ import {
fadeAnimation
]
})
export class EventConsumersPage implements OnInit, OnDestroy {
export class EventConsumersPageComponent extends ComponentBase implements OnInit, OnDestroy {
private subscription: Subscription;
public eventConsumerErrorDialog = new ModalView();
public eventConsumerError = '';
public eventConsumers = ImmutableArray.empty<EventConsumerDto>();
constructor(
constructor(notifications: NotificationService, users: UsersProviderService,
private readonly eventConsumersService: EventConsumersService
) {
super(notifications, users);
}
public ngOnInit() {
@ -59,6 +63,8 @@ export class EventConsumersPage implements OnInit, OnDestroy {
return e;
}
});
}, error => {
this.notifyError(error);
});
}
@ -72,6 +78,8 @@ export class EventConsumersPage implements OnInit, OnDestroy {
return e;
}
});
}, error => {
this.notifyError(error);
});
}
@ -85,6 +93,8 @@ export class EventConsumersPage implements OnInit, OnDestroy {
return e;
}
});
}, error => {
this.notifyError(error);
});
}

89
src/Squidex/app/features/administration/pages/users/users-page.component.html

@ -0,0 +1,89 @@
<sqx-title message="User Management"></sqx-title>
<sqx-panel panelWidth="50rem">
<div class="panel-header">
<div class="panel-title-row">
<div class="float-right">
<form class="form-inline" (ngSubmit)="search()">
<input class="form-control" [formControl]="usersFilter" placeholder="Search for user" />
</form>
</div>
<h3 class="panel-title">Users</h3>
</div>
<a class="panel-close" routerLink="../">
<i class="icon-close"></i>
</a>
</div>
<div class="panel-main">
<div class="panel-content panel-content-scroll">
<table class="table table-items table-fixed">
<colgroup>
<col style="width: 70px" />
<col style="width: 50%" />
<col style="width: 50%" />
<col style="width: 120px" />
</colgroup>
<thead>
<tr>
<th>
&nbsp;
</th>
<th>
Name
</th>
<th>
Email
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
<template ngFor let-user [ngForOf]="usersItems">
<tr>
<td>
<img class="user-picture" [attr.title]="user.name" [attr.src]="user.pictureUrl" />
</td>
<td>
<span class="user-name">{{user.displayName}}</span>
</td>
<td>
<span class="user-email">{{user.email}}</span>
</td>
<td class="col-right">
<span *ngIf="user.id !== currentUserId">
<button class="btn btn-simple" (click)="lock(user.id)" *ngIf="!user.isLocked" title="Lock User">
<i class="icon icon-unlocked"></i>
</button>
<button class="btn btn-simple" (click)="unlock(user.id)" *ngIf="user.isLocked" title="Unlock User">
<i class="icon icon-lock"></i>
</button>
</span>
</td>
</tr>
<tr class="spacer"></tr>
</template>
</tbody>
</table>
<div class="clearfix" *ngIf="usersTotal > 0">
<div class="float-right pagination">
<span class="pagination-text">{{itemFirst}}-{{itemLast}} of {{usersTotal}}</span>
<button class="btn btn-simple pagination-button" [disabled]="!canGoPrev" (click)="goPrev()">
<i class="icon-angle-left"></i>
</button>
<button class="btn btn-simple pagination-button" [disabled]="!canGoNext" (click)="goNext()">
<i class="icon-angle-right"></i>
</button>
</div>
</div>
</div>
</div>
</sqx-panel>

18
src/Squidex/app/features/administration/pages/users/users-page.component.scss

@ -0,0 +1,18 @@
@import '_vars';
@import '_mixins';
.col-right {
text-align: right;
}
.user {
&-name,
&-email {
@include truncate;
}
&-email {
font-style: italic;
font-size: .8rem;
}
}

135
src/Squidex/app/features/administration/pages/users/users-page.component.ts

@ -0,0 +1,135 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import {
AuthService,
ComponentBase,
ImmutableArray,
NotificationService,
UserDto,
UserManagementService,
UsersProviderService
} from 'shared';
@Component({
selector: 'sqx-users-page',
styleUrls: ['./users-page.component.scss'],
templateUrl: './users-page.component.html'
})
export class UsersPageComponent extends ComponentBase implements OnInit {
public currentUserId: string;
public usersItems = ImmutableArray.empty<UserDto>();
public usersTotal = 0;
public pageSize = 10;
public canGoNext = false;
public canGoPrev = false;
public itemFirst = 0;
public itemLast = 0;
public currentPage = 0;
public currentQuery = '';
public usersFilter = new FormControl();
constructor(notifications: NotificationService, users: UsersProviderService,
private readonly userManagementService: UserManagementService,
private readonly authService: AuthService
) {
super(notifications, users);
}
public ngOnInit() {
this.currentUserId = this.authService.user!.id;
this.load();
}
public search() {
this.currentPage = 0;
this.currentQuery = this.usersFilter.value;
this.load();
}
private load() {
this.userManagementService.getUsers(this.pageSize, this.currentPage * this.pageSize, this.currentQuery)
.subscribe(dtos => {
this.usersItems = ImmutableArray.of(dtos.items);
this.usersTotal = dtos.total;
this.updatePaging();
}, error => {
this.notifyError(error);
});
}
public lock(id: string) {
this.userManagementService.lockUser(id)
.subscribe(() => {
this.usersItems = this.usersItems.map(u => {
if (u.id === id) {
return new UserDto(u.id, u.email, u.displayName, u.pictureUrl, true);
} else {
return u;
}
});
}, error => {
this.notifyError(error);
});
}
public unlock(id: string) {
this.userManagementService.unlockUser(id)
.subscribe(() => {
this.usersItems = this.usersItems.map(u => {
if (u.id === id) {
return new UserDto(u.id, u.email, u.displayName, u.pictureUrl, false);
} else {
return u;
}
});
}, error => {
this.notifyError(error);
});
}
public goNext() {
if (this.canGoNext) {
this.currentPage++;
this.updatePaging();
this.load();
}
}
public goPrev() {
if (this.canGoPrev) {
this.currentPage--;
this.updatePaging();
this.load();
}
}
private updatePaging() {
const totalPages = Math.ceil(this.usersTotal / this.pageSize);
this.itemFirst = this.currentPage * this.pageSize + 1;
this.itemLast = Math.min(this.usersTotal, (this.currentPage + 1) * this.pageSize);
this.canGoNext = this.currentPage < totalPages - 1;
this.canGoPrev = this.currentPage > 0;
}
}

2
src/Squidex/app/features/content/pages/content/content-page.component.ts

@ -56,7 +56,7 @@ export class ContentPageComponent extends AppComponentBase implements OnDestroy,
private readonly router: Router,
private readonly messageBus: MessageBus
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnDestroy() {

2
src/Squidex/app/features/content/pages/contents/content-item.component.ts

@ -55,7 +55,7 @@ export class ContentItemComponent extends AppComponentBase implements OnInit {
public values: any[] = [];
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnInit() {

6
src/Squidex/app/features/content/pages/contents/contents-page.component.html

@ -10,9 +10,9 @@
<sqx-language-selector class="languages-buttons" (selectedLanguageChanged)="selectLanguage($event)" [languages]="languages"></sqx-language-selector>
<a class="btn btn-success" [routerLink]="['new']">
<button class="btn btn-success" [routerLink]="['new']">
<i class="icon-plus"></i> New
</a>
</button>
</div>
<h3 class="panel-title">{{schema|displayName}} Contents</h3>
@ -67,7 +67,7 @@
<div class="clearfix" *ngIf="contentTotal > 0">
<div class="float-right pagination">
{{itemFirst}}-{{itemLast}} of {{contentTotal}}
<span class="pagination-text">{{itemFirst}}-{{itemLast}} of {{contentTotal}}</span>
<button class="btn btn-simple pagination-button" [disabled]="!canGoPrev" (click)="goPrev()">
<i class="icon-angle-left"></i>

19
src/Squidex/app/features/content/pages/contents/contents-page.component.scss

@ -19,23 +19,4 @@
.form-inline {
display: inline-block;
}
.pagination {
& {
margin-top: 1rem;
}
&-button {
& {
color: $color-text;
font-size: 1.1rem;
font-weight: bold;
}
&:hover,
&.active {
color: darken($color-text, 20%);
}
}
}

3
src/Squidex/app/features/content/pages/contents/contents-page.component.ts

@ -73,7 +73,7 @@ export class ContentsPageComponent extends AppComponentBase implements OnDestroy
private readonly route: ActivatedRoute,
private readonly messageBus: MessageBus
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnDestroy() {
@ -107,6 +107,7 @@ export class ContentsPageComponent extends AppComponentBase implements OnDestroy
}
public search() {
this.currentPage = 0;
this.currentQuery = this.contentsFilter.value;
this.load();

2
src/Squidex/app/features/content/pages/schemas/schemas-page.component.ts

@ -56,7 +56,7 @@ export class SchemasPageComponent extends AppComponentBase {
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService,
private readonly schemasService: SchemasService
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
private loadSchemas(): Observable<SchemaDto[]> {

2
src/Squidex/app/features/dashboard/pages/dashboard-page.component.ts

@ -35,7 +35,7 @@ export class DashboardPageComponent extends AppComponentBase {
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService,
private readonly auth: AuthService
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnDestroy() {

2
src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts

@ -75,7 +75,7 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
private readonly formBuilder: FormBuilder,
private readonly route: ActivatedRoute
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnInit() {

2
src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts

@ -51,7 +51,7 @@ export class SchemasPageComponent extends AppComponentBase implements OnDestroy,
private readonly messageBus: MessageBus,
private readonly route: ActivatedRoute
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnDestroy() {

4
src/Squidex/app/features/settings/pages/clients/client.component.html

@ -22,9 +22,9 @@
<button type="submit" class="btn btn-primary" [disabled]="!renameForm.valid">Save</button>
<a class="btn btn-default btn-cancel" (click)="cancelRename()">
<button class="btn btn-default btn-cancel" (click)="cancelRename()">
<i class="icon-close"></i>
</a>
</button>
</form>
<span *ngIf="!isRenaming">

2
src/Squidex/app/features/settings/pages/clients/clients-page.component.ts

@ -46,7 +46,7 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
private readonly messageBus: MessageBus,
private readonly formBuilder: FormBuilder
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnInit() {

2
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html

@ -33,7 +33,7 @@
<th>
Email
</th>
<th>
<th colspan="2">
Actions
</th>
</tr>

15
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.scss

@ -1,21 +1,6 @@
@import '_vars';
@import '_mixins';
sqx-panel {
min-width: 50rem;
max-width: 50rem;
}
.card {
max-width: 44rem;
}
.contributors {
&-table {
margin: 0;
}
}
.user {
&-name,
&-email {

2
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts

@ -83,7 +83,7 @@ export class ContributorsPageComponent extends AppComponentBase implements OnIni
private readonly authService: AuthService,
private readonly formBuilder: FormBuilder
) {
super(apps, notifications, users);
super(notifications, users, apps);
this.usersDataSource = new UsersDataSource(usersService, this);
}

5
src/Squidex/app/features/settings/pages/languages/languages-page.component.scss

@ -1,11 +1,6 @@
@import '_vars';
@import '_mixins';
sqx-panel {
min-width: 42rem;
max-width: 42rem;
}
.language {
&-select {
width: 16rem;

2
src/Squidex/app/features/settings/pages/languages/languages-page.component.ts

@ -50,7 +50,7 @@ export class LanguagesPageComponent extends AppComponentBase implements OnInit {
private readonly messageBus: MessageBus,
private readonly formBuilder: FormBuilder
) {
super(apps, notifications, users);
super(notifications, users, apps);
}
public ngOnInit() {

67
src/Squidex/app/shared/components/app-component-base.ts

@ -9,76 +9,21 @@ import { Observable } from 'rxjs';
import {
AppsStoreService,
ErrorDto,
Notification,
NotificationService,
UsersProviderService
} from 'shared';
export abstract class AppComponentBase {
constructor(
private readonly appsStore: AppsStoreService,
private readonly notifications: NotificationService,
private readonly usersProvider: UsersProviderService
import { ComponentBase } from './component-base';
export abstract class AppComponentBase extends ComponentBase {
constructor(notifications: NotificationService, users: UsersProviderService,
private readonly appsStore: AppsStoreService
) {
super(notifications, users);
}
public appName(): Observable<string> {
return this.appsStore.selectedApp.map(a => a!.name).take(1);
}
public userEmail(userId: string, isRef: boolean = false): Observable<string> {
if (isRef) {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.usersProvider.getUser(parts[1]).map(u => u.email);
} else {
return null;
}
} else {
return this.usersProvider.getUser(userId).map(u => u.email);
}
}
public userPicture(userId: string, isRef: boolean = false): Observable<string> {
if (isRef) {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.usersProvider.getUser(parts[1]).map(u => u.pictureUrl);
} else {
return null;
}
} else {
return this.usersProvider.getUser(userId).map(u => u.pictureUrl);
}
}
public userName(userId: string, isRef: boolean = false, placeholder = 'Me'): Observable<string> {
if (isRef) {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.usersProvider.getUser(parts[1], placeholder).map(u => u.displayName);
} else {
return Observable.of(parts[1]);
}
} else {
return this.usersProvider.getUser(userId, placeholder).map(u => u.displayName);
}
}
public notifyError(error: string | ErrorDto) {
if (error instanceof ErrorDto) {
this.notifications.notify(Notification.error(error.displayMessage));
} else {
this.notifications.notify(Notification.error(error));
}
}
public notifyInfo(error: string) {
this.notifications.notify(Notification.error(error));
}
}

77
src/Squidex/app/shared/components/component-base.ts

@ -0,0 +1,77 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Observable } from 'rxjs';
import {
ErrorDto,
Notification,
NotificationService,
UsersProviderService
} from 'shared';
export abstract class ComponentBase {
constructor(
private readonly notifications: NotificationService,
private readonly users: UsersProviderService
) {
}
public userEmail(userId: string, isRef: boolean = false): Observable<string> {
if (isRef) {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.users.getUser(parts[1]).map(u => u.email);
} else {
return null;
}
} else {
return this.users.getUser(userId).map(u => u.email);
}
}
public userPicture(userId: string, isRef: boolean = false): Observable<string> {
if (isRef) {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.users.getUser(parts[1]).map(u => u.pictureUrl);
} else {
return null;
}
} else {
return this.users.getUser(userId).map(u => u.pictureUrl);
}
}
public userName(userId: string, isRef: boolean = false, placeholder = 'Me'): Observable<string> {
if (isRef) {
const parts = userId.split(':');
if (parts[0] === 'subject') {
return this.users.getUser(parts[1], placeholder).map(u => u.displayName);
} else {
return Observable.of(parts[1]);
}
} else {
return this.users.getUser(userId, placeholder).map(u => u.displayName);
}
}
protected notifyError(error: string | ErrorDto) {
if (error instanceof ErrorDto) {
this.notifications.notify(Notification.error(error.displayMessage));
} else {
this.notifications.notify(Notification.error(error));
}
}
protected notifyInfo(error: string) {
this.notifications.notify(Notification.error(error));
}
}

4
src/Squidex/app/shared/components/history.component.ts

@ -46,12 +46,12 @@ export class HistoryComponent extends AppComponentBase {
.switchMap(() => this.appName())
.switchMap(app => this.historyService.getHistory(app, this.channel).retry(2));
constructor(appsStore: AppsStoreService, notifications: NotificationService, usersProvider: UsersProviderService,
constructor(appsStore: AppsStoreService, notifications: NotificationService, users: UsersProviderService,
private readonly historyService: HistoryService,
private readonly messageBus: MessageBus,
private readonly route: ActivatedRoute
) {
super(appsStore, notifications, usersProvider);
super(notifications, users, appsStore);
}
public actorName(actor: string): Observable<string> {

4
src/Squidex/app/shared/components/language-selector.component.scss

@ -1,10 +1,6 @@
@import '_vars';
@import '_mixins';
.btn {
font-family: monospace;
}
.active {
color: $color-accent-dark;
}

1
src/Squidex/app/shared/declarations.ts

@ -7,6 +7,7 @@
export * from './components/app-component-base';
export * from './components/app-form.component';
export * from './components/component-base';
export * from './components/dashboard-link.directive';
export * from './components/help.component';
export * from './components/history.component';

2
src/Squidex/app/shared/module.ts

@ -34,6 +34,7 @@ import {
ResolvePublishedSchemaGuard,
ResolveSchemaGuard,
SchemasService,
UserManagementService,
UsersProviderService,
UsersService
} from './declarations';
@ -81,6 +82,7 @@ export class SqxSharedModule {
ResolvePublishedSchemaGuard,
ResolveSchemaGuard,
SchemasService,
UserManagementService,
UsersProviderService,
UsersService
]

1
src/Squidex/app/shared/services/app-clients.service.ts

@ -12,7 +12,6 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions';
import { ApiUrlConfig, DateTime } from 'framework';
import { AuthService } from './auth.service';
export class AppClientDto {

1
src/Squidex/app/shared/services/app-contributors.service.ts

@ -11,7 +11,6 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions';
import { ApiUrlConfig } from 'framework';
import { AuthService } from './auth.service';
export class AppContributorDto {

3
src/Squidex/app/shared/services/app-languages.service.ts

@ -11,7 +11,6 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions';
import { ApiUrlConfig } from 'framework';
import { AuthService } from './auth.service';
export class AppLanguageDto {
@ -60,7 +59,7 @@ export class AppLanguagesService {
item.isMasterLanguage === true);
});
})
.catchError('Failed to load languages. Please reload');
.catchError('Failed to load languages. Please reload.');
}
public postLanguages(appName: string, dto: AddAppLanguageDto): Observable<AppLanguageDto> {

3
src/Squidex/app/shared/services/history.service.ts

@ -11,7 +11,6 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions';
import { ApiUrlConfig, DateTime } from 'framework';
import { AuthService } from './auth.service';
export class HistoryEventDto {
@ -48,6 +47,6 @@ export class HistoryService {
DateTime.parseISO_UTC(item.created));
});
})
.catchError('Failed to load history. Please reload');
.catchError('Failed to load history. Please reload.');
}
}

3
src/Squidex/app/shared/services/languages.service.ts

@ -11,7 +11,6 @@ import { Observable } from 'rxjs';
import 'framework/angular/http-extensions';
import { ApiUrlConfig } from 'framework';
import { AuthService } from './auth.service';
export class LanguageDto {
@ -44,6 +43,6 @@ export class LanguageService {
item.englishName);
});
})
.catchError('Failed to load languages. Please reload');
.catchError('Failed to load languages. Please reload.');
}
}

12
src/Squidex/app/shared/services/users-provider.service.spec.ts

@ -28,7 +28,7 @@ describe('UsersProviderService', () => {
});
it('Should return users service when user not cached', () => {
const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image');
const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image', true);
usersService.setup(x => x.getUser('123'))
.returns(() => Observable.of(user)).verifiable(Times.once());
@ -45,7 +45,7 @@ describe('UsersProviderService', () => {
});
it('Should return provide user from cache', () => {
const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image');
const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image', true);
usersService.setup(x => x.getUser('123'))
.returns(() => Observable.of(user)).verifiable(Times.once());
@ -63,8 +63,8 @@ describe('UsersProviderService', () => {
usersService.verifyAll();
});
it('Should return Me when user is current user', () => {
const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image');
it('Should return me when user is current user', () => {
const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image', true);
authService.setup(x => x.user)
.returns(() => new Profile(<any>{ profile: { sub: '123'}}));
@ -78,7 +78,7 @@ describe('UsersProviderService', () => {
resultingUser = result;
}).unsubscribe();
expect(resultingUser).toEqual(new UserDto('123', 'mail@domain.com', 'Me', 'path/to/image'));
expect(resultingUser).toEqual(new UserDto('123', 'mail@domain.com', 'Me', 'path/to/image', true));
usersService.verifyAll();
});
@ -96,7 +96,7 @@ describe('UsersProviderService', () => {
resultingUser = result;
}).unsubscribe();
expect(resultingUser).toEqual(new UserDto('NOT FOUND', 'NOT FOUND', 'NOT FOUND', ''));
expect(resultingUser).toEqual(new UserDto('NOT FOUND', 'NOT FOUND', 'NOT FOUND', null, false));
usersService.verifyAll();
});

4
src/Squidex/app/shared/services/users-provider.service.ts

@ -29,7 +29,7 @@ export class UsersProviderService {
const request =
this.usersService.getUser(id).retry(2)
.catch(err => {
return Observable.of(new UserDto('NOT FOUND', 'NOT FOUND', 'NOT FOUND', ''));
return Observable.of(new UserDto('NOT FOUND', 'NOT FOUND', 'NOT FOUND', null, false));
})
.publishLast();
@ -41,7 +41,7 @@ export class UsersProviderService {
return result
.map(dto => {
if (this.authService.user && dto.id === this.authService.user.id) {
dto = new UserDto(dto.id, dto.email, me, dto.pictureUrl);
dto = new UserDto(dto.id, dto.email, me, dto.pictureUrl, dto.isLocked);
}
return dto;
}).share();

151
src/Squidex/app/shared/services/users.service.spec.ts

@ -7,12 +7,14 @@
import { Response, ResponseOptions } from '@angular/http';
import { Observable } from 'rxjs';
import { IMock, Mock, Times } from 'typemoq';
import { It, IMock, Mock, Times } from 'typemoq';
import {
ApiUrlConfig,
AuthService,
UserManagementService,
UserDto,
UsersDto,
UsersService
} from './../';
@ -34,12 +36,14 @@ describe('UsersService', () => {
id: '123',
email: 'mail1@domain.com',
displayName: 'User1',
pictureUrl: 'path/to/image1'
pictureUrl: 'path/to/image1',
isLocked: true
}, {
id: '456',
email: 'mail2@domain.com',
displayName: 'User2',
pictureUrl: 'path/to/image2'
pictureUrl: 'path/to/image2',
isLocked: true
}]
})
)
@ -54,14 +58,14 @@ describe('UsersService', () => {
expect(user).toEqual(
[
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1'),
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2')
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true),
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2', true)
]);
authService.verifyAll();
});
it('should make get request and query to get many users', () => {
it('should make get request with query to get many users', () => {
authService.setup(x => x.authGet('http://service/p/api/users/?query=my-query'))
.returns(() => Observable.of(
new Response(
@ -70,12 +74,14 @@ describe('UsersService', () => {
id: '123',
email: 'mail1@domain.com',
displayName: 'User1',
pictureUrl: 'path/to/image1'
pictureUrl: 'path/to/image1',
isLocked: true
}, {
id: '456',
email: 'mail2@domain.com',
displayName: 'User2',
pictureUrl: 'path/to/image2'
pictureUrl: 'path/to/image2',
isLocked: true
}]
})
)
@ -90,8 +96,8 @@ describe('UsersService', () => {
expect(user).toEqual(
[
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1'),
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2')
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true),
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2', true)
]);
authService.verifyAll();
@ -106,7 +112,8 @@ describe('UsersService', () => {
id: '123',
email: 'mail1@domain.com',
displayName: 'User1',
pictureUrl: 'path/to/image1'
pictureUrl: 'path/to/image1',
isLocked: true
}
})
)
@ -119,7 +126,127 @@ describe('UsersService', () => {
user = result;
}).unsubscribe();
expect(user).toEqual(new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1'));
expect(user).toEqual(new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true));
authService.verifyAll();
});
});
describe('UserManagementService', () => {
let authService: IMock<AuthService>;
let userManagementService: UserManagementService;
beforeEach(() => {
authService = Mock.ofType(AuthService);
userManagementService = new UserManagementService(authService.object, new ApiUrlConfig('http://service/p/'));
});
it('should make get request to get many users', () => {
authService.setup(x => x.authGet('http://service/p/api/user-management/?take=20&skip=30&query='))
.returns(() => Observable.of(
new Response(
new ResponseOptions({
body: {
total: 100,
items: [{
id: '123',
email: 'mail1@domain.com',
displayName: 'User1',
pictureUrl: 'path/to/image1',
isLocked: true
}, {
id: '456',
email: 'mail2@domain.com',
displayName: 'User2',
pictureUrl: 'path/to/image2',
isLocked: true
}]
}
})
)
))
.verifiable(Times.once());
let user: UsersDto | null = null;
userManagementService.getUsers(20, 30).subscribe(result => {
user = result;
}).unsubscribe();
expect(user).toEqual(
new UsersDto(100, [
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true),
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2', true)
]));
authService.verifyAll();
});
it('should make get request with query to get many users', () => {
authService.setup(x => x.authGet('http://service/p/api/user-management/?take=20&skip=30&query=my-query'))
.returns(() => Observable.of(
new Response(
new ResponseOptions({
body: {
total: 100,
items: [{
id: '123',
email: 'mail1@domain.com',
displayName: 'User1',
pictureUrl: 'path/to/image1',
isLocked: true
}, {
id: '456',
email: 'mail2@domain.com',
displayName: 'User2',
pictureUrl: 'path/to/image2',
isLocked: true
}]
}
})
)
))
.verifiable(Times.once());
let user: UsersDto | null = null;
userManagementService.getUsers(20, 30, 'my-query').subscribe(result => {
user = result;
}).unsubscribe();
expect(user).toEqual(
new UsersDto(100, [
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true),
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2', true)
]));
authService.verifyAll();
});
it('should make put request to lock user', () => {
authService.setup(x => x.authPut('http://service/p/api/user-management/123/lock', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
userManagementService.lockUser('123');
authService.verifyAll();
});
it('should make put request to unlock user', () => {
authService.setup(x => x.authPut('http://service/p/api/user-management/123/unlock', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
userManagementService.unlockUser('123');
authService.verifyAll();
});

71
src/Squidex/app/shared/services/users.service.ts

@ -8,16 +8,26 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { ApiUrlConfig } from 'framework';
import 'framework/angular/http-extensions';
import { ApiUrlConfig } from 'framework';
import { AuthService } from './auth.service';
export class UsersDto {
constructor(
public readonly total: number,
public readonly items: UserDto[]
) {
}
}
export class UserDto {
constructor(
public readonly id: string,
public readonly email: string,
public readonly displayName: string,
public readonly pictureUrl: string
public readonly pictureUrl: string,
public readonly isLocked: boolean
) {
}
}
@ -43,9 +53,11 @@ export class UsersService {
item.id,
item.email,
item.displayName,
item.pictureUrl);
item.pictureUrl,
item.isLocked);
});
});
})
.catchError('Failed to load users. Please reload.');
}
public getUser(id: string): Observable<UserDto> {
@ -58,7 +70,54 @@ export class UsersService {
response.id,
response.email,
response.displayName,
response.pictureUrl);
});
response.pictureUrl,
response.isLocked);
})
.catchError('Failed to load user. Please reload.');
}
}
@Injectable()
export class UserManagementService {
constructor(
private readonly authService: AuthService,
private readonly apiUrl: ApiUrlConfig
) {
}
public getUsers(take: number, skip: number, query?: string): Observable<UsersDto> {
const url = this.apiUrl.buildUrl(`api/user-management/?take=${take}&skip=${skip}&query=${query || ''}`);
return this.authService.authGet(url)
.map(response => response.json())
.map(response => {
const items: any[] = response.items;
const users = items.map(item => {
return new UserDto(
item.id,
item.email,
item.displayName,
item.pictureUrl,
item.isLocked);
});
return new UsersDto(response.total, users);
})
.catchError('Failed to load users. Please reload.');
}
public lockUser(id: string): Observable<any> {
const url = this.apiUrl.buildUrl(`api/user-management/${id}/lock`);
return this.authService.authPut(url, {})
.catchError('Failed to load users. Please retry.');
}
public unlockUser(id: string): Observable<any> {
const url = this.apiUrl.buildUrl(`api/user-management/${id}/unlock`);
return this.authService.authPut(url, {})
.catchError('Failed to load users. Please retry.');
}
}

2
src/Squidex/app/shell/pages/app/app-area.component.scss

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

46
src/Squidex/app/shell/pages/app/left-menu.component.scss

@ -1,46 +1,2 @@
@import '_mixins';
@import '_vars';
.sidebar {
@include fixed($size-navbar-height, auto, 0, 0);
@include box-shadow-colored(2px, 0, 0, $color-dark1-border2);
min-width: $size-sidebar-width;
max-width: $size-sidebar-width;
border-right: 1px solid $color-dark1-border1;
background: $color-dark1-background;
z-index: 100;
}
.nav {
&-icon {
font-size: 2rem;
}
&-text {
font-size: .9rem;
}
&-link {
& {
@include transition(color .3s ease);
padding: 1.25rem;
display: block;
text-align: center;
text-decoration: none;
color: $color-dark1-foreground;
}
&:hover,
&.active {
color: $color-dark1-focus-foreground;
.nav-icon {
color: $color-theme-blue;
}
}
&.active {
background: $color-dark1-active-background;
}
}
}
@import '_vars';

24
src/Squidex/app/theme/_lists.scss

@ -81,4 +81,28 @@
border: 0;
height: .3rem;
}
}
.pagination {
& {
margin-top: 1rem;
}
&-text {
line-height: 2.2rem;
}
&-button {
& {
color: $color-text;
font-size: 1.1rem;
font-weight: bold;
margin-left: .4rem;
}
&:hover,
&.active {
color: darken($color-text, 20%);
}
}
}

47
src/Squidex/app/theme/_panels.scss

@ -168,4 +168,51 @@
.nav-link {
@include transition(color .4s ease);
}
}
.sidebar {
& {
@include fixed($size-navbar-height, auto, 0, 0);
@include box-shadow-colored(2px, 0, 0, $color-dark1-border2);
min-width: $size-sidebar-width;
max-width: $size-sidebar-width;
border-right: 1px solid $color-dark1-border1;
background: $color-dark1-background;
z-index: 100;
}
.nav {
&-icon {
font-size: 2rem;
}
&-text {
font-size: .9rem;
}
&-link {
& {
@include transition(color .3s ease);
padding: 1.25rem;
display: block;
text-align: center;
text-decoration: none;
color: $color-dark1-foreground;
}
&:hover,
&.active {
color: $color-dark1-focus-foreground;
.nav-icon {
color: $color-theme-blue;
}
}
&.active {
background: $color-dark1-active-background;
}
}
}
}

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

@ -0,0 +1,158 @@
body {
padding: 0;
margin: 0;
font-family: sans-serif;
font-size: 1em;
line-height: 1.5;
color: #555;
background: #fff;
}
h1 {
font-size: 1.5em;
font-weight: normal;
}
small {
font-size: .66666667em;
}
a {
color: #e74c3c;
text-decoration: none;
}
a:hover, a:focus {
box-shadow: 0 1px #e74c3c;
}
.bshadow0, input {
box-shadow: inset 0 -2px #e7e7e7;
}
input:hover {
box-shadow: inset 0 -2px #ccc;
}
input, fieldset {
font-family: sans-serif;
font-size: 1em;
margin: 0;
padding: 0;
border: 0;
}
input {
color: inherit;
line-height: 1.5;
height: 1.5em;
padding: .25em 0;
}
input:focus {
outline: none;
box-shadow: inset 0 -2px #449fdb;
}
.glyph {
font-size: 16px;
width: 15em;
padding-bottom: 1em;
margin-right: 4em;
margin-bottom: 1em;
float: left;
overflow: hidden;
}
.liga {
width: 80%;
width: calc(100% - 2.5em);
}
.talign-right {
text-align: right;
}
.talign-center {
text-align: center;
}
.bgc1 {
background: #f1f1f1;
}
.fgc1 {
color: #999;
}
.fgc0 {
color: #000;
}
p {
margin-top: 1em;
margin-bottom: 1em;
}
.mvm {
margin-top: .75em;
margin-bottom: .75em;
}
.mtn {
margin-top: 0;
}
.mtl, .mal {
margin-top: 1.5em;
}
.mbl, .mal {
margin-bottom: 1.5em;
}
.mal, .mhl {
margin-left: 1.5em;
margin-right: 1.5em;
}
.mhmm {
margin-left: 1em;
margin-right: 1em;
}
.mls {
margin-left: .25em;
}
.ptl {
padding-top: 1.5em;
}
.pbs, .pvs {
padding-bottom: .25em;
}
.pvs, .pts {
padding-top: .25em;
}
.unit {
float: left;
}
.unitRight {
float: right;
}
.size1of2 {
width: 50%;
}
.size1of1 {
width: 100%;
}
.clearfix:before, .clearfix:after {
content: " ";
display: table;
}
.clearfix:after {
clear: both;
}
.hidden-true {
display: none;
}
.textbox0 {
width: 3em;
background: #f1f1f1;
padding: .25em .5em;
line-height: 1.5;
height: 1.5em;
}
#testDrive {
display: block;
padding-top: 24px;
line-height: 1.5;
}
.fs0 {
font-size: 16px;
}
.fs1 {
font-size: 28px;
}
.fs2 {
font-size: 32px;
}
.fs3 {
font-size: 32px;
}

30
src/Squidex/app/theme/icomoon/demo-files/demo.js

@ -0,0 +1,30 @@
if (!('boxShadow' in document.body.style)) {
document.body.setAttribute('class', 'noBoxShadow');
}
document.body.addEventListener("click", function(e) {
var target = e.target;
if (target.tagName === "INPUT" &&
target.getAttribute('class').indexOf('liga') === -1) {
target.select();
}
});
(function() {
var fontSize = document.getElementById('fontSize'),
testDrive = document.getElementById('testDrive'),
testText = document.getElementById('testText');
function updateTest() {
testDrive.innerHTML = testText.value || String.fromCharCode(160);
if (window.icomoonLiga) {
window.icomoonLiga(testDrive);
}
}
function updateSize() {
testDrive.style.fontSize = fontSize.value + 'px';
}
fontSize.addEventListener('change', updateSize, false);
testText.addEventListener('input', updateTest, false);
testText.addEventListener('change', updateTest, false);
updateSize();
}());

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

@ -0,0 +1,988 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>IcoMoon Demo</title>
<meta name="description" content="An Icon Font Generated By IcoMoon.io">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="demo-files/demo.css">
<link rel="stylesheet" href="style.css"></head>
<body>
<div class="bgc1 clearfix">
<h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;54)</small></h1>
</div>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 14</h1>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-angle-right">
</span>
<span class="mls"> icon-angle-right</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e931" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe931;" 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="clearfix bshadow0 pbs">
<span class="icon-caret-right">
</span>
<span class="mls"> icon-caret-right</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e929" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe929;" 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="clearfix bshadow0 pbs">
<span class="icon-caret-left">
</span>
<span class="mls"> icon-caret-left</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92a;" 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="clearfix bshadow0 pbs">
<span class="icon-caret-up">
</span>
<span class="mls"> icon-caret-up</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92b;" 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="clearfix bshadow0 pbs">
<span class="icon-caret-down">
</span>
<span class="mls"> icon-caret-down</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92c" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92c;" 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="clearfix bshadow0 pbs">
<span class="icon-angle-up">
</span>
<span class="mls"> icon-angle-up</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e903" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe903;" 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="clearfix bshadow0 pbs">
<span class="icon-angle-down">
</span>
<span class="mls"> icon-angle-down</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e900" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe900;" 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="clearfix bshadow0 pbs">
<span class="icon-angle-left">
</span>
<span class="mls"> icon-angle-left</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e901" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe901;" 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>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 16</h1>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-lock">
</span>
<span class="mls"> icon-lock</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e98f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe98f;" 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="lock, secure" class="liga unitRight" />
</div>
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-unlocked">
</span>
<span class="mls"> icon-unlocked</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e990" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe990;" 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="unlocked, lock-open" class="liga unitRight" />
</div>
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-warning">
</span>
<span class="mls"> icon-warning</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="ea07" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xea07;" 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="warning, sign" class="liga unitRight" />
</div>
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-notification">
</span>
<span class="mls"> icon-notification</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="ea08" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xea08;" 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="notification, warning2" class="liga unitRight" />
</div>
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-reset">
</span>
<span class="mls"> icon-reset</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92e;" 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 fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-pause">
</span>
<span class="mls"> icon-pause</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92f;" 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 fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-play">
</span>
<span class="mls"> icon-play</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e930" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe930;" 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 fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-settings2">
</span>
<span class="mls"> icon-settings2</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92d;" 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 fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-bin2">
</span>
<span class="mls"> icon-bin2</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e902" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe902;" 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>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: Unknown</h1>
<div class="glyph fs3">
<div class="clearfix bshadow0 pbs">
<span class="icon-activity">
</span>
<span class="mls"> icon-activity</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e904" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe904;" 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-history">
</span>
<span class="mls"> icon-history</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e904" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe904;" 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-time">
</span>
<span class="mls"> icon-time</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e904" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe904;" 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-add">
</span>
<span class="mls"> icon-add</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e905" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe905;" 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-plus">
</span>
<span class="mls"> icon-plus</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e905" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe905;" 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-check-circle">
</span>
<span class="mls"> icon-check-circle</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e906" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe906;" 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-check-circle-filled">
</span>
<span class="mls"> icon-check-circle-filled</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e907" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe907;" 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-close">
</span>
<span class="mls"> icon-close</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e908" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe908;" 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-content">
</span>
<span class="mls"> icon-content</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e909" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe909;" 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-control-checkbox">
</span>
<span class="mls"> icon-control-checkbox</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e90a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe90a;" 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-control-dropdown">
</span>
<span class="mls"> icon-control-dropdown</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e90b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe90b;" 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-control-input">
</span>
<span class="mls"> icon-control-input</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e90c" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe90c;" 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-control-radio">
</span>
<span class="mls"> icon-control-radio</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e90d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe90d;" 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-control-textarea">
</span>
<span class="mls"> icon-control-textarea</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e90e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe90e;" 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-control-toggle">
</span>
<span class="mls"> icon-control-toggle</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e90f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe90f;" 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-copy">
</span>
<span class="mls"> icon-copy</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e910" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe910;" 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-dashboard">
</span>
<span class="mls"> icon-dashboard</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e911" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe911;" 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-delete">
</span>
<span class="mls"> icon-delete</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e912" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe912;" 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-bin">
</span>
<span class="mls"> icon-bin</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e912" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe912;" 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-delete-filled">
</span>
<span class="mls"> icon-delete-filled</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e913" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe913;" 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-document-delete">
</span>
<span class="mls"> icon-document-delete</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e914" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe914;" 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-document-disable">
</span>
<span class="mls"> icon-document-disable</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e915" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe915;" 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-document-publish">
</span>
<span class="mls"> icon-document-publish</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e916" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe916;" 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-drag">
</span>
<span class="mls"> icon-drag</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e917" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe917;" 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-filter">
</span>
<span class="mls"> icon-filter</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e918" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe918;" 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-help">
</span>
<span class="mls"> icon-help</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e919" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe919;" 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-json">
</span>
<span class="mls"> icon-json</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e91a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe91a;" 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-location">
</span>
<span class="mls"> icon-location</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e91b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe91b;" 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-logo">
</span>
<span class="mls"> icon-logo</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e91c" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe91c;" 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-media">
</span>
<span class="mls"> icon-media</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e91d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe91d;" 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-more">
</span>
<span class="mls"> icon-more</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e91e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe91e;" 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-dots">
</span>
<span class="mls"> icon-dots</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e91e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe91e;" 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-pencil">
</span>
<span class="mls"> icon-pencil</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e91f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe91f;" 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-reference">
</span>
<span class="mls"> icon-reference</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e920" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe920;" 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-schemas">
</span>
<span class="mls"> icon-schemas</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e921" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe921;" 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-search">
</span>
<span class="mls"> icon-search</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e922" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe922;" 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-settings">
</span>
<span class="mls"> icon-settings</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e923" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe923;" 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-type-boolean">
</span>
<span class="mls"> icon-type-boolean</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e924" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe924;" 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-type-datetime">
</span>
<span class="mls"> icon-type-datetime</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e925" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe925;" 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-type-number">
</span>
<span class="mls"> icon-type-number</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e926" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe926;" 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-type-string">
</span>
<span class="mls"> icon-type-string</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e927" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe927;" 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-user">
</span>
<span class="mls"> icon-user</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e928" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe928;" 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>
<!--[if gt IE 8]><!-->
<div class="mhl clearfix mbl">
<h1>Font Test Drive</h1>
<label>
Font Size: <input id="fontSize" type="number" class="textbox0 mbm"
min="8" value="48" />
px
</label>
<input id="testText" type="text" class="phl size1of1 mvl"
placeholder="Type some text to test..." value=""/>
<div id="testDrive" class="icon-">&nbsp;
</div>
</div>
<!--<![endif]-->
<div class="bgc1 clearfix">
<p class="mhl">Generated by <a href="https://icomoon.io/app">IcoMoon</a></p>
</div>
<script src="demo-files/demo.js"></script>
</body>
</html>

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

Binary file not shown.

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

@ -47,7 +47,7 @@
<glyph unicode="&#xe925;" glyph-name="type-datetime" d="M947.2 857.6h-128v25.6c0 14.131-11.469 25.6-25.6 25.6s-25.6-11.469-25.6-25.6v-25.6h-512v25.6c0 14.131-11.52 25.6-25.6 25.6s-25.6-11.469-25.6-25.6v-25.6h-128c-42.342 0-76.8-34.458-76.8-76.8v-716.8c0-42.342 34.458-76.8 76.8-76.8h870.4c42.342 0 76.8 34.458 76.8 76.8v716.8c0 42.342-34.458 76.8-76.8 76.8zM972.8 64c0-14.131-11.469-25.6-25.6-25.6h-870.4c-14.080 0-25.6 11.469-25.6 25.6v537.6h921.6v-537.6zM972.8 652.8h-921.6v128c0 14.080 11.52 25.6 25.6 25.6h128v-76.8c0-14.080 11.52-25.6 25.6-25.6s25.6 11.52 25.6 25.6v76.8h512v-76.8c0-14.080 11.469-25.6 25.6-25.6s25.6 11.52 25.6 25.6v76.8h128c14.131 0 25.6-11.52 25.6-25.6v-128zM332.8 448h51.2c14.080 0 25.6 11.52 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.52-25.6-25.6s11.52-25.6 25.6-25.6zM486.4 448h51.2c14.131 0 25.6 11.52 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.52-25.6-25.6s11.52-25.6 25.6-25.6zM640 448h51.2c14.131 0 25.6 11.52 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.52-25.6-25.6s11.469-25.6 25.6-25.6zM793.6 448h51.2c14.131 0 25.6 11.52 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.52-25.6-25.6s11.469-25.6 25.6-25.6zM179.2 345.6h51.2c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM332.8 345.6h51.2c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM486.4 345.6h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM640 345.6h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6zM793.6 345.6h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6zM179.2 243.2h51.2c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM332.8 243.2h51.2c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM486.4 243.2h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM640 243.2h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6zM793.6 243.2h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6zM179.2 140.8h51.2c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM332.8 140.8h51.2c14.080 0 25.6 11.469 25.6 25.6s-11.52 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM486.4 140.8h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.080 0-25.6-11.469-25.6-25.6s11.52-25.6 25.6-25.6zM640 140.8h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6zM793.6 140.8h51.2c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-51.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6z" />
<glyph unicode="&#xe926;" glyph-name="type-number" d="M256 294.4h-76.8v332.8c0 14.131-11.469 25.6-25.6 25.6h-76.8c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6h51.2v-307.2h-76.8c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6h204.8c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6zM614.4 652.8h-204.8c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6h179.2v-128h-179.2c-14.131 0-25.6-11.469-25.6-25.6v-179.2c0-14.131 11.469-25.6 25.6-25.6h204.8c14.131 0 25.6 11.469 25.6 25.6s-11.469 25.6-25.6 25.6h-179.2v128h179.2c14.131 0 25.6 11.469 25.6 25.6v179.2c0 14.131-11.469 25.6-25.6 25.6zM972.8 652.8h-204.8c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6h179.2v-128h-179.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6h179.2v-128h-179.2c-14.131 0-25.6-11.469-25.6-25.6s11.469-25.6 25.6-25.6h204.8c14.131 0 25.6 11.469 25.6 25.6v358.4c0 14.131-11.469 25.6-25.6 25.6z" />
<glyph unicode="&#xe927;" glyph-name="type-string" d="M870.4 38.4h-716.8c-14.131 0-25.6-11.443-25.6-25.6s11.469-25.6 25.6-25.6h716.8c14.157 0 25.6 11.443 25.6 25.6s-11.443 25.6-25.6 25.6zM194.688 142.848c13.030-5.555 28.083 0.461 33.613 13.44l125.030 291.712h317.338l125.005-291.712c4.173-9.677 13.568-15.488 23.526-15.488 3.405 0 6.81 0.64 10.112 2.048 13.005 5.606 18.995 20.659 13.44 33.638l-131.61 306.944c-0.051 0.051-0.051 0.154-0.102 0.205l-175.488 409.6c-4.045 9.472-13.312 15.565-23.552 15.565s-19.507-6.093-23.552-15.514l-175.488-409.6c-0.051-0.051-0.051-0.154-0.102-0.205l-131.61-306.97c-5.53-13.005 0.461-28.058 13.44-33.664zM512 818.227l136.704-319.027h-273.408l136.704 319.027z" />
<glyph unicode="&#xe928;" glyph-name="user" d="M765.248 256c0-35.392-28.352-64-63.296-64h-379.904c-34.88 0-63.232 28.608-63.232 64 0 0.704-6.4 0.064 0 0 30.336 91.776 137.6 128 253.184 128 115.84 0 223.104-35.776 253.248-128 6.144 0 0 0.064 0 0zM385.344 576c0 70.656 56.704 128 126.656 128s126.656-57.344 126.656-128-56.704-192-126.656-192-126.656 121.344-126.656 192z" />
<glyph unicode="&#xe928;" glyph-name="user" d="M955.221 112c0 0.109 10.752 0 0 0-52.751 161.392-240.461 224-443.178 224-202.269 0-389.979-63.392-443.066-224-11.2 0.109 0 1.232 0 0 0-61.936 49.615-112 110.654-112h664.823c61.151 0 110.766 50.064 110.766 112zM290.399 672c0-123.648 99.231-336 221.645-336s221.645 212.352 221.645 336c0 123.648-99.231 224-221.645 224s-221.645-100.352-221.645-224z" />
<glyph unicode="&#xe929;" glyph-name="caret-right" horiz-adv-x="329" d="M329.143 438.857c0-9.714-4-18.857-10.857-25.714l-256-256c-6.857-6.857-16-10.857-25.714-10.857-20 0-36.571 16.571-36.571 36.571v512c0 20 16.571 36.571 36.571 36.571 9.714 0 18.857-4 25.714-10.857l256-256c6.857-6.857 10.857-16 10.857-25.714z" />
<glyph unicode="&#xe92a;" glyph-name="caret-left" horiz-adv-x="402" d="M365.714 694.857v-512c0-20-16.571-36.571-36.571-36.571-9.714 0-18.857 4-25.714 10.857l-256 256c-6.857 6.857-10.857 16-10.857 25.714s4 18.857 10.857 25.714l256 256c6.857 6.857 16 10.857 25.714 10.857 20 0 36.571-16.571 36.571-36.571z" />
<glyph unicode="&#xe92b;" glyph-name="caret-up" horiz-adv-x="585" d="M585.143 256c0-20-16.571-36.571-36.571-36.571h-512c-20 0-36.571 16.571-36.571 36.571 0 9.714 4 18.857 10.857 25.714l256 256c6.857 6.857 16 10.857 25.714 10.857s18.857-4 25.714-10.857l256-256c6.857-6.857 10.857-16 10.857-25.714z" />
@ -56,6 +56,9 @@
<glyph unicode="&#xe92e;" glyph-name="reset" d="M889.68 793.68c-93.608 102.216-228.154 166.32-377.68 166.32-282.77 0-512-229.23-512-512h96c0 229.75 186.25 416 416 416 123.020 0 233.542-53.418 309.696-138.306l-149.696-149.694h352v352l-134.32-134.32zM928 448c0-229.75-186.25-416-416-416-123.020 0-233.542 53.418-309.694 138.306l149.694 149.694h-352v-352l134.32 134.32c93.608-102.216 228.154-166.32 377.68-166.32 282.77 0 512 229.23 512 512h-96z" />
<glyph unicode="&#xe92f;" glyph-name="pause" d="M128 832h320v-768h-320zM576 832h320v-768h-320z" />
<glyph unicode="&#xe930;" glyph-name="play" d="M192 832l640-384-640-384z" />
<glyph unicode="&#xe931;" glyph-name="angle-right" horiz-adv-x="347" d="M340 402.286c0-4.571-2.286-9.714-5.714-13.143l-266.286-266.286c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-28.571 28.571c-3.429 3.429-5.714 8-5.714 13.143 0 4.571 2.286 9.714 5.714 13.143l224.571 224.571-224.571 224.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l28.571 28.571c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l266.286-266.286c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xe98f;" glyph-name="lock" d="M592 512h-16v192c0 105.87-86.13 192-192 192h-128c-105.87 0-192-86.13-192-192v-192h-16c-26.4 0-48-21.6-48-48v-480c0-26.4 21.6-48 48-48h544c26.4 0 48 21.6 48 48v480c0 26.4-21.6 48-48 48zM192 704c0 35.29 28.71 64 64 64h128c35.29 0 64-28.71 64-64v-192h-256v192z" />
<glyph unicode="&#xe990;" glyph-name="unlocked" d="M768 896c105.87 0 192-86.13 192-192v-192h-128v192c0 35.29-28.71 64-64 64h-128c-35.29 0-64-28.71-64-64v-192h16c26.4 0 48-21.6 48-48v-480c0-26.4-21.6-48-48-48h-544c-26.4 0-48 21.6-48 48v480c0 26.4 21.6 48 48 48h400v192c0 105.87 86.13 192 192 192h128z" />
<glyph unicode="&#xea07;" glyph-name="warning" d="M512 867.226l429.102-855.226h-858.206l429.104 855.226zM512 960c-22.070 0-44.14-14.882-60.884-44.648l-437.074-871.112c-33.486-59.532-5-108.24 63.304-108.24h869.308c68.3 0 96.792 48.708 63.3 108.24h0.002l-437.074 871.112c-16.742 29.766-38.812 44.648-60.882 44.648v0zM576 128c0-35.346-28.654-64-64-64s-64 28.654-64 64c0 35.346 28.654 64 64 64s64-28.654 64-64zM512 256c-35.346 0-64 28.654-64 64v192c0 35.346 28.654 64 64 64s64-28.654 64-64v-192c0-35.346-28.654-64-64-64z" />
<glyph unicode="&#xea08;" glyph-name="notification" d="M512 864c-111.118 0-215.584-43.272-294.156-121.844s-121.844-183.038-121.844-294.156c0-111.118 43.272-215.584 121.844-294.156s183.038-121.844 294.156-121.844c111.118 0 215.584 43.272 294.156 121.844s121.844 183.038 121.844 294.156c0 111.118-43.272 215.584-121.844 294.156s-183.038 121.844-294.156 121.844zM512 960v0c282.77 0 512-229.23 512-512s-229.23-512-512-512c-282.77 0-512 229.23-512 512s229.23 512 512 512zM448 256h128v-128h-128zM448 768h128v-384h-128z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 41 KiB

After

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

24
src/Squidex/app/theme/icomoon/icons/user.svg

@ -19,7 +19,7 @@
enable-background="new 0 0 16 16"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="User.svg"><metadata
sodipodi:docname="user.svg"><metadata
id="metadata9"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
@ -32,20 +32,18 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="742"
inkscape:window-height="480"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview5"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-x="2795"
inkscape:window-y="313"
inkscape:window-maximized="0"
inkscape:cx="-3.8983051"
inkscape:cy="10.711864"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" /><path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#438CEF"
d="M11.957,11c0,0.553-0.443,1-0.989,1H5.032 c-0.545,0-0.988-0.447-0.988-1c0-0.011-0.1-0.001,0,0C4.518,9.566,6.194,9,8,9C9.81,9,11.486,9.559,11.957,11 C12.053,11,11.957,10.999,11.957,11z M6.021,6c0-1.104,0.886-2,1.979-2s1.979,0.896,1.979,2S9.093,9,8,9S6.021,7.104,6.021,6z"
d="m 14.925334,13.25 c 0,0.96775 -0.775238,1.75 -1.730725,1.75 L 2.8067528,15 C 1.853016,15 1.0777767,14.21775 1.0777767,13.25 c 0,-0.01925 -0.17499759,-0.0017 0,0 0.8294885,-2.5095 3.762448,-3.5000004 6.9229044,-3.5000004 3.1674559,0 6.1004149,0.9782504 6.9246529,3.5000004 0.167998,0 0,-0.0017 0,0 z M 4.5374788,4.4999993 c 0,-1.9320002 1.5504787,-3.5000003 3.4632023,-3.5000003 1.9127229,0 3.4632019,1.5680001 3.4632019,3.5000003 0,1.9320001 -1.550479,5.2500003 -3.4632019,5.2500003 -1.9127236,0 -3.4632023,-3.3180002 -3.4632023,-5.2500003 z"
id="path3"
style="fill:#000000" /></svg>
style="clip-rule:evenodd;fill:#000000;fill-rule:evenodd"
inkscape:connector-curvature="0" /></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

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

@ -1,6 +1,304 @@
{
"IcoMoonType": "selection",
"icons": [
{
"icon": {
"paths": [
"M340 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8-5.714-13.143 0-4.571 2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"
],
"attrs": [
{}
],
"width": 347,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"angle-right"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 1,
"id": 0,
"prevSize": 28,
"code": 59697,
"name": "angle-right"
},
"setIdx": 0,
"setId": 4,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M329.143 512c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-512c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"
],
"attrs": [
{}
],
"width": 329,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-right"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 1,
"id": 7,
"prevSize": 28,
"code": 59689,
"name": "caret-right"
},
"setIdx": 3,
"setId": 1,
"iconIdx": 39
},
{
"icon": {
"paths": [
"M365.714 256v512c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"
],
"attrs": [
{}
],
"width": 402,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-left"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 2,
"id": 6,
"prevSize": 28,
"code": 59690,
"name": "caret-left"
},
"setIdx": 3,
"setId": 1,
"iconIdx": 40
},
{
"icon": {
"paths": [
"M585.143 694.857c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"
],
"attrs": [
{}
],
"width": 585,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-up"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 3,
"id": 5,
"prevSize": 28,
"code": 59691,
"name": "caret-up"
},
"setIdx": 3,
"setId": 1,
"iconIdx": 41
},
{
"icon": {
"paths": [
"M585.143 402.286c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"
],
"attrs": [
{}
],
"width": 585,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-down"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 4,
"id": 4,
"prevSize": 28,
"code": 59692,
"name": "caret-down"
},
"setIdx": 3,
"setId": 1,
"iconIdx": 42
},
{
"icon": {
"paths": [
"M614.286 676.571c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"
],
"attrs": [
{}
],
"width": 658,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"angle-up"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 2,
"id": 2,
"prevSize": 28,
"code": 59651,
"name": "angle-up"
},
"setIdx": 3,
"setId": 1,
"iconIdx": 43
},
{
"icon": {
"paths": [
"M614.286 420.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"
],
"attrs": [
{}
],
"width": 658,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"angle-down"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 1,
"id": 1,
"prevSize": 28,
"code": 59648,
"name": "angle-down"
},
"setIdx": 3,
"setId": 1,
"iconIdx": 44
},
{
"icon": {
"paths": [
"M358.286 310.857c0 4.571-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8 5.714 13.143z"
],
"attrs": [
{}
],
"width": 384,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"angle-left"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 2,
"id": 0,
"prevSize": 28,
"code": 59649,
"name": "angle-left"
},
"setIdx": 3,
"setId": 1,
"iconIdx": 45
},
{
"icon": {
"paths": [
"M592 448h-16v-192c0-105.87-86.13-192-192-192h-128c-105.87 0-192 86.13-192 192v192h-16c-26.4 0-48 21.6-48 48v480c0 26.4 21.6 48 48 48h544c26.4 0 48-21.6 48-48v-480c0-26.4-21.6-48-48-48zM192 256c0-35.29 28.71-64 64-64h128c35.29 0 64 28.71 64 64v192h-256v-192z"
],
"attrs": [],
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"lock",
"secure",
"private",
"encrypted"
],
"defaultCode": 59791,
"grid": 16
},
"attrs": [],
"properties": {
"ligatures": "lock, secure",
"name": "lock",
"id": 143,
"order": 54,
"prevSize": 32,
"code": 59791
},
"setIdx": 1,
"setId": 3,
"iconIdx": 143
},
{
"icon": {
"paths": [
"M768 64c105.87 0 192 86.13 192 192v192h-128v-192c0-35.29-28.71-64-64-64h-128c-35.29 0-64 28.71-64 64v192h16c26.4 0 48 21.6 48 48v480c0 26.4-21.6 48-48 48h-544c-26.4 0-48-21.6-48-48v-480c0-26.4 21.6-48 48-48h400v-192c0-105.87 86.13-192 192-192h128z"
],
"attrs": [],
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"unlocked",
"lock-open"
],
"defaultCode": 59792,
"grid": 16
},
"attrs": [],
"properties": {
"ligatures": "unlocked, lock-open",
"name": "unlocked",
"id": 144,
"order": 53,
"prevSize": 32,
"code": 59792
},
"setIdx": 1,
"setId": 3,
"iconIdx": 144
},
{
"icon": {
"paths": [
@ -27,7 +325,7 @@
"prevSize": 32,
"code": 59911
},
"setIdx": 0,
"setIdx": 1,
"setId": 3,
"iconIdx": 263
},
@ -58,7 +356,7 @@
"prevSize": 32,
"code": 59912
},
"setIdx": 0,
"setIdx": 1,
"setId": 3,
"iconIdx": 264
},
@ -97,7 +395,7 @@
"code": 59694,
"name": "reset"
},
"setIdx": 1,
"setIdx": 2,
"setId": 2,
"iconIdx": 0
},
@ -127,7 +425,7 @@
"code": 59695,
"name": "pause"
},
"setIdx": 1,
"setIdx": 2,
"setId": 2,
"iconIdx": 1
},
@ -157,7 +455,7 @@
"code": 59696,
"name": "play"
},
"setIdx": 1,
"setIdx": 2,
"setId": 2,
"iconIdx": 2
},
@ -192,7 +490,7 @@
"code": 59693,
"name": "settings2"
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 0
},
@ -229,7 +527,7 @@
"prevSize": 32,
"code": 59650
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 1
},
@ -258,7 +556,7 @@
"prevSize": 32,
"code": 59652
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 2
},
@ -287,7 +585,7 @@
"prevSize": 32,
"code": 59653
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 3
},
@ -316,7 +614,7 @@
"prevSize": 32,
"code": 59654
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 4
},
@ -345,7 +643,7 @@
"prevSize": 32,
"code": 59655
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 5
},
@ -374,7 +672,7 @@
"prevSize": 32,
"code": 59656
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 6
},
@ -403,7 +701,7 @@
"prevSize": 32,
"code": 59657
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 7
},
@ -432,7 +730,7 @@
"prevSize": 32,
"code": 59658
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 8
},
@ -461,7 +759,7 @@
"prevSize": 32,
"code": 59659
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 9
},
@ -490,7 +788,7 @@
"prevSize": 32,
"code": 59660
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 10
},
@ -519,7 +817,7 @@
"prevSize": 32,
"code": 59661
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 11
},
@ -548,7 +846,7 @@
"prevSize": 32,
"code": 59662
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 12
},
@ -577,7 +875,7 @@
"prevSize": 32,
"code": 59663
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 13
},
@ -606,7 +904,7 @@
"prevSize": 32,
"code": 59664
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 14
},
@ -635,7 +933,7 @@
"prevSize": 32,
"code": 59665
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 15
},
@ -664,7 +962,7 @@
"prevSize": 32,
"code": 59666
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 16
},
@ -693,7 +991,7 @@
"prevSize": 32,
"code": 59667
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 17
},
@ -722,7 +1020,7 @@
"prevSize": 32,
"code": 59668
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 18
},
@ -751,7 +1049,7 @@
"prevSize": 32,
"code": 59669
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 19
},
@ -780,7 +1078,7 @@
"prevSize": 32,
"code": 59670
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 20
},
@ -809,7 +1107,7 @@
"prevSize": 32,
"code": 59671
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 21
},
@ -838,7 +1136,7 @@
"prevSize": 32,
"code": 59672
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 22
},
@ -867,7 +1165,7 @@
"prevSize": 32,
"code": 59673
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 23
},
@ -896,7 +1194,7 @@
"prevSize": 32,
"code": 59674
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 24
},
@ -925,7 +1223,7 @@
"prevSize": 32,
"code": 59675
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 25
},
@ -954,7 +1252,7 @@
"prevSize": 32,
"code": 59676
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 26
},
@ -983,7 +1281,7 @@
"prevSize": 32,
"code": 59677
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 27
},
@ -1012,7 +1310,7 @@
"prevSize": 32,
"code": 59678
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 28
},
@ -1041,7 +1339,7 @@
"prevSize": 32,
"code": 59679
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 29
},
@ -1070,7 +1368,7 @@
"prevSize": 32,
"code": 59680
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 30
},
@ -1099,7 +1397,7 @@
"prevSize": 32,
"code": 59681
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 31
},
@ -1128,7 +1426,7 @@
"prevSize": 32,
"code": 59682
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 32
},
@ -1157,7 +1455,7 @@
"prevSize": 32,
"code": 59683
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 33
},
@ -1186,7 +1484,7 @@
"prevSize": 32,
"code": 59684
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 34
},
@ -1215,7 +1513,7 @@
"prevSize": 32,
"code": 59685
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 35
},
@ -1244,7 +1542,7 @@
"prevSize": 32,
"code": 59686
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 36
},
@ -1273,14 +1571,14 @@
"prevSize": 32,
"code": 59687
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 37
},
{
"icon": {
"paths": [
"M765.248 704c0 35.392-28.352 64-63.296 64h-379.904c-34.88 0-63.232-28.608-63.232-64 0-0.704-6.4-0.064 0 0 30.336-91.776 137.6-128 253.184-128 115.84 0 223.104 35.776 253.248 128 6.144 0 0-0.064 0 0zM385.344 384c0-70.656 56.704-128 126.656-128s126.656 57.344 126.656 128-56.704 192-126.656 192-126.656-121.344-126.656-192z"
"M955.221 848c0-0.109 10.752 0 0 0-52.751-161.392-240.461-224-443.178-224-202.269 0-389.979 63.392-443.066 224-11.2-0.109 0-1.232 0 0 0 61.936 49.615 112 110.654 112h664.823c61.151 0 110.766-50.064 110.766-112zM290.399 288c0 123.648 99.231 336 221.645 336s221.645-212.352 221.645-336c0-123.648-99.231-224-221.645-224s-221.645 100.352-221.645 224z"
],
"attrs": [
{}
@ -1302,219 +1600,9 @@
"prevSize": 32,
"code": 59688
},
"setIdx": 2,
"setIdx": 3,
"setId": 1,
"iconIdx": 38
},
{
"icon": {
"paths": [
"M329.143 512c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-512c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"
],
"attrs": [
{}
],
"width": 329,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-right"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 1,
"id": 7,
"prevSize": 28,
"code": 59689,
"name": "caret-right"
},
"setIdx": 2,
"setId": 1,
"iconIdx": 39
},
{
"icon": {
"paths": [
"M365.714 256v512c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"
],
"attrs": [
{}
],
"width": 402,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-left"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 2,
"id": 6,
"prevSize": 28,
"code": 59690,
"name": "caret-left"
},
"setIdx": 2,
"setId": 1,
"iconIdx": 40
},
{
"icon": {
"paths": [
"M585.143 694.857c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"
],
"attrs": [
{}
],
"width": 585,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-up"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 3,
"id": 5,
"prevSize": 28,
"code": 59691,
"name": "caret-up"
},
"setIdx": 2,
"setId": 1,
"iconIdx": 41
},
{
"icon": {
"paths": [
"M585.143 402.286c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"
],
"attrs": [
{}
],
"width": 585,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"caret-down"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 4,
"id": 4,
"prevSize": 28,
"code": 59692,
"name": "caret-down"
},
"setIdx": 2,
"setId": 1,
"iconIdx": 42
},
{
"icon": {
"paths": [
"M614.286 676.571c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"
],
"attrs": [
{}
],
"width": 658,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"angle-up"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 2,
"id": 2,
"prevSize": 28,
"code": 59651,
"name": "angle-up"
},
"setIdx": 2,
"setId": 1,
"iconIdx": 43
},
{
"icon": {
"paths": [
"M614.286 420.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"
],
"attrs": [
{}
],
"width": 658,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"angle-down"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 1,
"id": 1,
"prevSize": 28,
"code": 59648,
"name": "angle-down"
},
"setIdx": 2,
"setId": 1,
"iconIdx": 44
},
{
"icon": {
"paths": [
"M358.286 310.857c0 4.571-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8 5.714 13.143z"
],
"attrs": [
{}
],
"width": 384,
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"angle-left"
],
"grid": 14
},
"attrs": [
{}
],
"properties": {
"order": 2,
"id": 0,
"prevSize": 28,
"code": 59649,
"name": "angle-left"
},
"setIdx": 2,
"setId": 1,
"iconIdx": 45
}
],
"height": 1024,

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

@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?prmkzn');
src: url('fonts/icomoon.eot?prmkzn#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?prmkzn') format('truetype'),
url('fonts/icomoon.woff?prmkzn') format('woff'),
url('fonts/icomoon.svg?prmkzn#icomoon') format('svg');
src: url('fonts/icomoon.eot?ondpxx');
src: url('fonts/icomoon.eot?ondpxx#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?ondpxx') format('truetype'),
url('fonts/icomoon.woff?ondpxx') format('woff'),
url('fonts/icomoon.svg?ondpxx#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
@ -24,6 +24,36 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-angle-right:before {
content: "\e931";
}
.icon-caret-right:before {
content: "\e929";
}
.icon-caret-left:before {
content: "\e92a";
}
.icon-caret-up:before {
content: "\e92b";
}
.icon-caret-down:before {
content: "\e92c";
}
.icon-angle-up:before {
content: "\e903";
}
.icon-angle-down:before {
content: "\e900";
}
.icon-angle-left:before {
content: "\e901";
}
.icon-lock:before {
content: "\e98f";
}
.icon-unlocked:before {
content: "\e990";
}
.icon-warning:before {
content: "\ea07";
}
@ -171,25 +201,4 @@
.icon-user:before {
content: "\e928";
}
.icon-caret-right:before {
content: "\e929";
}
.icon-caret-left:before {
content: "\e92a";
}
.icon-caret-up:before {
content: "\e92b";
}
.icon-caret-down:before {
content: "\e92c";
}
.icon-angle-up:before {
content: "\e903";
}
.icon-angle-down:before {
content: "\e900";
}
.icon-angle-left:before {
content: "\e901";
}

Loading…
Cancel
Save