Browse Source

Some progress

pull/1/head
Sebastian 10 years ago
parent
commit
283c39a85a
  1. 6
      src/Squidex.Infrastructure/CQRS/EventStore/EventStoreBus.cs
  2. 12
      src/Squidex.Read/ITrackCreatedByEntity.cs
  3. 1
      src/Squidex.Store.MongoDb/Apps/MongoAppEntity.cs
  4. 2
      src/Squidex.Write/Apps/AppCommandHandler.cs
  5. 3
      src/Squidex/Controllers/Api/Schemas/Models/AddFieldDto.cs
  6. 135
      src/Squidex/Controllers/Api/Schemas/Models/Converters/JsonInheritanceConverter.cs
  7. 2
      src/Squidex/Controllers/Api/Schemas/Models/FieldPropertiesDto.cs
  8. 2
      src/Squidex/Controllers/Api/Schemas/Models/NumberFieldPropertiesDto.cs
  9. 2
      src/Squidex/Controllers/Api/Schemas/Models/StringFieldPropertiesDto.cs
  10. 32
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.html
  11. 101
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  12. 2
      src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html
  13. 4
      src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts
  14. 1
      src/Squidex/app/features/settings/pages/clients/client.component.html
  15. 4
      src/Squidex/app/features/settings/pages/clients/client.component.ts
  16. 28
      src/Squidex/app/features/settings/pages/clients/clients-page.component.html
  17. 2
      src/Squidex/app/features/settings/pages/clients/clients-page.component.ts
  18. 2
      src/Squidex/app/shared/components/app-form.component.html
  19. 4
      src/Squidex/app/shared/components/app-form.component.ts
  20. 49
      src/Squidex/app/shared/services/schemas.service.ts
  21. 2
      src/Squidex/app/shell/pages/internal/apps-menu.component.html

6
src/Squidex.Infrastructure/CQRS/EventStore/EventStoreBus.cs

@ -81,7 +81,7 @@ namespace Squidex.Infrastructure.CQRS.EventStore
return; return;
} }
this.streamName = streamToConnect; streamName = streamToConnect;
SubscribeLive(); SubscribeLive();
SubscribeCatch(); SubscribeCatch();
@ -145,7 +145,7 @@ namespace Squidex.Infrastructure.CQRS.EventStore
connection.SubscribeToStreamFrom(streamName, position, settings, connection.SubscribeToStreamFrom(streamName, position, settings,
(subscription, resolvedEvent) => (subscription, resolvedEvent) =>
{ {
OnCatchEvent(consumer, streamName, resolvedEvent, subscriptionName, subscription); OnCatchEvent(consumer, resolvedEvent, subscriptionName, subscription);
}, userCredentials: credentials); }, userCredentials: credentials);
lock (catchSubscriptions) lock (catchSubscriptions)
@ -175,7 +175,7 @@ namespace Squidex.Infrastructure.CQRS.EventStore
} }
} }
private void OnCatchEvent(IEventConsumer consumer, string streamName, ResolvedEvent resolvedEvent, string subscriptionName, EventStoreCatchUpSubscription subscription) private void OnCatchEvent(IEventConsumer consumer, ResolvedEvent resolvedEvent, string subscriptionName, EventStoreCatchUpSubscription subscription)
{ {
if (resolvedEvent.OriginalEvent.EventStreamId.StartsWith("$", StringComparison.OrdinalIgnoreCase)) if (resolvedEvent.OriginalEvent.EventStreamId.StartsWith("$", StringComparison.OrdinalIgnoreCase))
{ {

12
src/Squidex.Read/ITrackCreatedByEntity.cs

@ -1,7 +1,11 @@
using System; // ==========================================================================
using System.Collections.Generic; // ITrackCreatedByEntity.cs
using System.Linq; // Squidex Headless CMS
using System.Threading.Tasks; // ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure; using Squidex.Infrastructure;
namespace Squidex.Read namespace Squidex.Read

1
src/Squidex.Store.MongoDb/Apps/MongoAppEntity.cs

@ -6,7 +6,6 @@
// All rights reserved. // All rights reserved.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;

2
src/Squidex.Write/Apps/AppCommandHandler.cs

@ -64,7 +64,7 @@ namespace Squidex.Write.Apps
if (await userRepository.FindUserByIdAsync(command.ContributorId) == null) if (await userRepository.FindUserByIdAsync(command.ContributorId) == null)
{ {
var error = var error =
new ValidationError($"Cannot find contributor the contributor", new ValidationError("Cannot find contributor the contributor",
nameof(AssignContributor.ContributorId)); nameof(AssignContributor.ContributorId));
throw new ValidationException("Cannot assign contributor to app", error); throw new ValidationException("Cannot assign contributor to app", error);

3
src/Squidex/Controllers/Api/Schemas/Models/AddFieldDto.cs

@ -8,6 +8,8 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
// ReSharper disable ConvertIfStatementToReturnStatement
namespace Squidex.Controllers.Api.Schemas.Models namespace Squidex.Controllers.Api.Schemas.Models
{ {
public sealed class AddFieldDto public sealed class AddFieldDto
@ -26,3 +28,4 @@ namespace Squidex.Controllers.Api.Schemas.Models
public FieldPropertiesDto Properties { get; set; } public FieldPropertiesDto Properties { get; set; }
} }
} }

135
src/Squidex/Controllers/Api/Schemas/Models/Converters/JsonInheritanceConverter.cs

@ -0,0 +1,135 @@
// ==========================================================================
// JsonInheritanceConverter.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NJsonSchema.Annotations;
// ReSharper disable ConvertIfStatementToReturnStatement
namespace Squidex.Controllers.Api.Schemas.Models.Converters
{
public sealed class JsonInheritanceConverter : JsonConverter
{
private readonly string discriminator;
[ThreadStatic]
private static bool isReading;
[ThreadStatic]
private static bool isWriting;
public override bool CanWrite
{
get
{
if (!isWriting)
{
return true;
}
return isWriting = false;
}
}
public override bool CanRead
{
get
{
if (!isReading)
{
return true;
}
return isReading = false;
}
}
public JsonInheritanceConverter(string discriminator)
{
this.discriminator = discriminator;
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
isWriting = true;
try
{
var jsonObject = JObject.FromObject(value, serializer);
jsonObject.AddFirst(new JProperty(discriminator, GetSchemaName(value.GetType())));
writer.WriteToken(jsonObject.CreateReader());
}
finally
{
isWriting = false;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
isReading = true;
try
{
var jsonObject = serializer.Deserialize<JObject>(reader);
var subName = jsonObject[discriminator]?.Value<string>();
if (subName == null)
{
return null;
}
var subType = GetObjectSubtype(objectType, subName);
if (subType == null)
{
return null;
}
return serializer.Deserialize(jsonObject.CreateReader(), subType);
}
finally
{
isReading = false;
}
}
private static Type GetObjectSubtype(Type objectType, string discriminatorValue)
{
var knownTypeAttribute =
objectType.GetTypeInfo().GetCustomAttributes<KnownTypeAttribute>()
.FirstOrDefault(a => IsKnownType(a, discriminatorValue));
return knownTypeAttribute?.Type;
}
private static bool IsKnownType(KnownTypeAttribute attribute, string discriminator)
{
var type = attribute.Type;
return type != null && GetSchemaName(type) == discriminator;
}
private static string GetSchemaName(Type type)
{
var schenaName = type.GetTypeInfo().GetCustomAttribute<JsonSchemaAttribute>()?.Name;
return schenaName ?? type.Name;
}
}
}

2
src/Squidex/Controllers/Api/Schemas/Models/FieldPropertiesDto.cs

@ -9,7 +9,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Newtonsoft.Json; using Newtonsoft.Json;
using NJsonSchema.Converters; using Squidex.Controllers.Api.Schemas.Models.Converters;
using Squidex.Core.Schemas; using Squidex.Core.Schemas;
namespace Squidex.Controllers.Api.Schemas.Models namespace Squidex.Controllers.Api.Schemas.Models

2
src/Squidex/Controllers/Api/Schemas/Models/NumberFieldPropertiesDto.cs

@ -12,7 +12,7 @@ using Squidex.Infrastructure.Reflection;
namespace Squidex.Controllers.Api.Schemas.Models namespace Squidex.Controllers.Api.Schemas.Models
{ {
[JsonSchema("Number")] [JsonSchema("number")]
public sealed class NumberFieldPropertiesDto : FieldPropertiesDto public sealed class NumberFieldPropertiesDto : FieldPropertiesDto
{ {
/// <summary> /// <summary>

2
src/Squidex/Controllers/Api/Schemas/Models/StringFieldPropertiesDto.cs

@ -12,7 +12,7 @@ using Squidex.Infrastructure.Reflection;
namespace Squidex.Controllers.Api.Schemas.Models namespace Squidex.Controllers.Api.Schemas.Models
{ {
[JsonSchema("String")] [JsonSchema("string")]
public sealed class StringFieldPropertiesDto : FieldPropertiesDto public sealed class StringFieldPropertiesDto : FieldPropertiesDto
{ {
/// <summary> /// <summary>

32
src/Squidex/app/features/schemas/pages/schema/schema-page.component.html

@ -1,9 +1,9 @@
<sqx-title message="{app} | Schema" parameter1="app" value1="{{appName() | async}}"></sqx-title> <sqx-title message="{app} | {schema}" parameter1="app" value1="{{appName() | async}}" parameter="schema" value2="{{schemaName | async}}"></sqx-title>
<div class="panel panel-light"> <div class="panel panel-light">
<div class="panel-header"> <div class="panel-header">
<div> <div>
<h3 class="panel-title">Schema</h3> <h3 class="panel-title">{{schemaName | async}}</h3>
<a class="panel-close" routerLink="../"> <a class="panel-close" routerLink="../">
<i class="icon-close"></i> <i class="icon-close"></i>
@ -12,5 +12,33 @@
</div> </div>
<div class="panel-content"> <div class="panel-content">
<div class="table-items-footer">
<form class="form-inline" [formGroup]="addFieldForm" (submit)="addField()">
<div class="form-group">
<select class="form-control" formControlName="type">
<option *ngFor="let type of fieldTypes">{{type}}</option>
</select>
</div>
<div class="form-group">
<div class="errors-box" *ngIf="addFieldForm.get('name').invalid && addFieldForm.get('name').dirty">
<div class="errors">
<span *ngIf="addFieldForm.get('name').hasError('required')">
Name is required.
</span>
<span *ngIf="addFieldForm.get('name').hasError('maxlength')">
Name can not have more than 40 characters.
</span>
<span *ngIf="addFieldForm.get('name').hasError('pattern')">
Name can contain lower case letters (a-z), numbers and dashes (not at the end).
</span>
</div>
</div>
<input type="text" class="form-control" formControlName="name" maxlength="40" placeholder="Enter field name" />
</div>
<button type="submit" class="btn btn-success" [disabled]="addFieldForm.invalid">Add Field</button>
</form>
</div>
</div> </div>
</div> </div>

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

@ -6,27 +6,120 @@
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { import {
AddFieldDto,
AppComponentBase, AppComponentBase,
AppsStoreService, AppsStoreService,
FieldDto,
FieldPropertiesDto,
HistoryChannelUpdated,
ImmutableArray,
MessageBus,
NotificationService, NotificationService,
NumberFieldPropertiesDto,
SchemaDetailsDto,
SchemasService, SchemasService,
StringFieldPropertiesDto,
UsersProviderService UsersProviderService
} from 'shared'; } from 'shared';
const FALLBACK_NAME = 'my-schema';
@Component({ @Component({
selector: 'sqx-schema-page', selector: 'sqx-schema-page',
styleUrls: ['./schema-page.component.scss'], styleUrls: ['./schema-page.component.scss'],
templateUrl: './schema-page.component.html' templateUrl: './schema-page.component.html'
}) })
export class SchemaPageComponent extends AppComponentBase { export class SchemaPageComponent extends AppComponentBase implements OnInit {
public fieldTypes: string[] = [
'string',
'number'
];
public schemaFields = ImmutableArray.empty<FieldDto>();
public addFieldForm: FormGroup =
this.formBuilder.group({
type: ['string',
[
Validators.required
]],
name: ['',
[
Validators.required,
Validators.maxLength(40),
Validators.pattern('[a-z0-9]+(\-[a-z0-9]+)*')
]]
});
public get schemaName(): Observable<string> {
return this.route.params.map(p => p['schemaName']);
}
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService, constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService,
private readonly schemasService: SchemasService private readonly schemasService: SchemasService,
private readonly messageBus: MessageBus,
private readonly formBuilder: FormBuilder,
private readonly route: ActivatedRoute
) { ) {
super(apps, notifications, users); super(apps, notifications, users);
} }
public ngOnInit() {
this.load();
}
public load() {
this.schemaName.combineLatest(this.appName(), (schemaName, appName) => { return { schemaName, appName }; })
.switchMap(p => this.schemasService.getSchema(p.appName, p.schemaName)).retry(2)
.subscribe(dto => {
this.schemaFields = ImmutableArray.of(dto.fields);
}, error => {
this.notifyError(error);
});
}
public addField() {
this.addFieldForm.markAsTouched();
if (this.addFieldForm.valid) {
this.addFieldForm.disable();
let properties: FieldPropertiesDto;
switch (this.addFieldForm.get('type').value) {
case 'string':
properties = new StringFieldPropertiesDto();
break;
case 'number':
properties = new NumberFieldPropertiesDto();
}
const dto = new AddFieldDto(this.addFieldForm.get('name').value, properties);
const reset = () => {
this.addFieldForm.reset();
this.addFieldForm.enable();
};
this.schemaName.combineLatest(this.appName(), (schemaName, appName) => { return { schemaName, appName }; })
.switchMap(p => this.schemasService.postField(p.appName, p.schemaName, dto))
.subscribe(dto => {
this.updateFields(this.schemaFields.push(new FieldDto(this.addFieldForm.get('name').value, false, false, properties)));
reset();
}, error => {
this.notifyError(error);
reset();
});
}
}
private updateFields(fields: ImmutableArray<FieldDto>) {
this.schemaFields = fields;
this.messageBus.publish(new HistoryChannelUpdated());
}
} }

2
src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html

@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<input type="text" class="form-control" id="schema-name" formControlName="name" /> <input type="text" class="form-control" formControlName="name" />
<span class="form-hint"> <span class="form-hint">
<p> <p>

4
src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts

@ -61,7 +61,7 @@ export class SchemaFormComponent implements OnInit {
} }
public ngOnInit() { public ngOnInit() {
this.createForm.controls['name'].valueChanges.subscribe(value => { this.createForm.get('name').valueChanges.subscribe(value => {
this.schemaName = value || FALLBACK_NAME; this.schemaName = value || FALLBACK_NAME;
}); });
} }
@ -72,7 +72,7 @@ export class SchemaFormComponent implements OnInit {
if (this.createForm.valid) { if (this.createForm.valid) {
this.createForm.disable(); this.createForm.disable();
const name = this.createForm.controls['name'].value; const name = this.createForm.get('name').value;
const dto = new CreateSchemaDto(name); const dto = new CreateSchemaDto(name);
const now = DateTime.now(); const now = DateTime.now();

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

@ -22,6 +22,7 @@
</span> </span>
</div> </div>
</div> </div>
<input type="text" class="form-control" formControlName="name" maxlength="20" sqxFocusOnInit (keydown)="onKeyDown($event.keyCode)" /> <input type="text" class="form-control" formControlName="name" maxlength="20" sqxFocusOnInit (keydown)="onKeyDown($event.keyCode)" />
</div> </div>

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

@ -74,7 +74,7 @@ export class ClientComponent {
} }
public resetForm() { public resetForm() {
this.renameForm.controls['name'].setValue(this.clientName); this.renameForm.get('name').setValue(this.clientName);
} }
public cancelRename() { public cancelRename() {
@ -95,7 +95,7 @@ export class ClientComponent {
public rename() { public rename() {
try { try {
const newName = this.renameForm.controls['name'].value; const newName = this.renameForm.get('name').value;
if (newName !== this.clientName) { if (newName !== this.clientName) {
this.renamed.emit(newName); this.renamed.emit(newName);

28
src/Squidex/app/features/settings/pages/clients/clients-page.component.html

@ -21,22 +21,22 @@
<div class="table-items-footer"> <div class="table-items-footer">
<form class="form-inline" [formGroup]="addClientForm" (submit)="attachClient()"> <form class="form-inline" [formGroup]="addClientForm" (submit)="attachClient()">
<div class="errors-box" *ngIf="addClientForm.get('name').invalid && addClientForm.get('name').dirty"> <div class="form-group">
<div class="errors"> <div class="errors-box" *ngIf="addClientForm.get('name').invalid && addClientForm.get('name').dirty">
<span *ngIf="addClientForm.get('name').hasError('required')"> <div class="errors">
Name is required. <span *ngIf="addClientForm.get('name').hasError('required')">
</span> Name is required.
<span *ngIf="addClientForm.get('name').hasError('maxlength')"> </span>
Name can not have more than 40 characters. <span *ngIf="addClientForm.get('name').hasError('maxlength')">
</span> Name can not have more than 40 characters.
<span *ngIf="addClientForm.get('name').hasError('pattern')"> </span>
Name can contain lower case letters (a-z), numbers and dashes (not at the end). <span *ngIf="addClientForm.get('name').hasError('pattern')">
</span> Name can contain lower case letters (a-z), numbers and dashes (not at the end).
</span>
</div>
</div> </div>
</div>
<div class="form-group"> <input type="text" class="form-control" formControlName="name" maxlength="40" placeholder="Enter client name" />
<input type="text" class="form-control" id="app-name" formControlName="name" maxlength="40" placeholder="Enter client name" />
</div> </div>
<button type="submit" class="btn btn-success" [disabled]="addClientForm.invalid">Add Client</button> <button type="submit" class="btn btn-success" [disabled]="addClientForm.invalid">Add Client</button>

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

@ -94,7 +94,7 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit {
if (this.addClientForm.valid) { if (this.addClientForm.valid) {
this.addClientForm.disable(); this.addClientForm.disable();
const dto = new CreateAppClientDto(this.addClientForm.controls['name'].value); const dto = new CreateAppClientDto(this.addClientForm.get('name').value);
const reset = () => { const reset = () => {
this.addClientForm.reset(); this.addClientForm.reset();

2
src/Squidex/app/shared/components/app-form.component.html

@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<input type="text" class="form-control" id="app-name" formControlName="name" /> <input type="text" class="form-control" formControlName="name" />
<span class="form-hint"> <span class="form-hint">
<p> <p>

4
src/Squidex/app/shared/components/app-form.component.ts

@ -53,7 +53,7 @@ export class AppFormComponent implements OnInit {
} }
public ngOnInit() { public ngOnInit() {
this.createForm.controls['name'].valueChanges.subscribe(value => { this.createForm.get('name').valueChanges.subscribe(value => {
this.appName = value || FALLBACK_NAME; this.appName = value || FALLBACK_NAME;
}); });
} }
@ -64,7 +64,7 @@ export class AppFormComponent implements OnInit {
if (this.createForm.valid) { if (this.createForm.valid) {
this.createForm.disable(); this.createForm.disable();
const dto = new CreateAppDto(this.createForm.controls['name'].value); const dto = new CreateAppDto(this.createForm.get('name').value);
this.appsStore.createApp(dto) this.appsStore.createApp(dto)
.subscribe(dto => { .subscribe(dto => {

49
src/Squidex/app/shared/services/schemas.service.ts

@ -63,30 +63,30 @@ export abstract class FieldPropertiesDto {
} }
export class NumberFieldPropertiesDto extends FieldPropertiesDto { export class NumberFieldPropertiesDto extends FieldPropertiesDto {
constructor(label: string, hints: string, placeholder: string, isRequired: boolean, constructor(label?: string, hints?: string, placeholder?: string, isRequired: boolean = false,
public readonly defaultValue: number | null, public readonly defaultValue?: number | null,
public readonly maxValue: number | null, public readonly maxValue?: number | null,
public readonly minValue: number | null, public readonly minValue?: number | null,
public readonly allowedValues: number[] public readonly allowedValues?: number[]
) { ) {
super(label, hints, placeholder, isRequired); super(label, hints, placeholder, isRequired);
this['$type'] = 'Number'; this['fieldType'] = 'number';
} }
} }
export class StringFieldPropertiesDto extends FieldPropertiesDto { export class StringFieldPropertiesDto extends FieldPropertiesDto {
constructor(label: string, hints: string, placeholder: string, isRequired: boolean, constructor(label?: string, hints?: string, placeholder?: string, isRequired: boolean = false,
public readonly defaultValue: string, public readonly defaultValue?: string,
public readonly pattern: string, public readonly pattern?: string,
public readonly patternMessage: string, public readonly patternMessage?: string,
public readonly minLength: number | null, public readonly minLength?: number | null,
public readonly maxLength: number | null, public readonly maxLength?: number | null,
public readonly allowedValues: number[] public readonly allowedValues?: string[]
) { ) {
super(label, hints, placeholder, isRequired); super(label, hints, placeholder, isRequired);
this['$type'] = 'String'; this['fieldType'] = 'string';
} }
} }
@ -98,6 +98,14 @@ export class UpdateSchemaDto {
} }
} }
export class AddFieldDto {
constructor(
public readonly name: string,
public readonly properties: FieldPropertiesDto
) {
}
}
export class UpdateFieldDto { export class UpdateFieldDto {
constructor( constructor(
public readonly properties: FieldPropertiesDto public readonly properties: FieldPropertiesDto
@ -142,7 +150,7 @@ export class SchemasService {
} }
public getSchema(appName: string, id: string): Observable<SchemaDetailsDto> { public getSchema(appName: string, id: string): Observable<SchemaDetailsDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/{id}`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${id}`);
return this.authService.authGet(url) return this.authService.authGet(url)
.map(response => response.json()) .map(response => response.json())
@ -206,4 +214,15 @@ export class SchemasService {
}) })
.catch(response => handleError('Failed to create schema. Please reload.', response)); .catch(response => handleError('Failed to create schema. Please reload.', response));
} }
public postField(appName: string, schemaName: string, dto: AddFieldDto): Observable<EntityCreatedDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/`);
return this.authService.authPost(url, dto)
.map(response => response.json())
.map(response => {
return new EntityCreatedDto(response.id);
})
.catch(response => handleError('Failed to add field. Please reload.', response));
}
} }

2
src/Squidex/app/shell/pages/internal/apps-menu.component.html

@ -17,7 +17,7 @@
</div> </div>
<div class="drodown-button"> <div class="drodown-button">
<button class="btn btn-block btn-success" id="app-create" (click)="createApp()"><i class="icon-plus"></i> Create New App</button> <button class="btn btn-block btn-success" (click)="createApp()"><i class="icon-plus"></i> Create New App</button>
</div> </div>
</div> </div>
</li> </li>

Loading…
Cancel
Save