Browse Source

Reordering of Fields with Drag and Drop. #10

pull/65/head
Sebastian Stehle 9 years ago
parent
commit
f4e5d76b17
  1. 5
      src/Squidex.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs
  2. 2
      src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs
  3. 2
      src/Squidex/app/app.module.ts
  4. 5
      src/Squidex/app/features/schemas/module.ts
  5. 4
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.html
  6. 4
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss
  7. 12
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  8. 39
      src/Squidex/app/features/schemas/utils/sorted.directive.ts
  9. 6
      src/Squidex/app/framework/utils/immutable-array.spec.ts
  10. 4
      src/Squidex/app/framework/utils/immutable-array.ts
  11. 16
      src/Squidex/app/shared/services/schemas.service.spec.ts
  12. 7
      src/Squidex/app/shared/services/schemas.service.ts
  13. 3
      src/Squidex/app/theme/theme.scss
  14. 1
      src/Squidex/package.json

5
src/Squidex.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs

@ -73,6 +73,11 @@ namespace Squidex.Read.MongoDb.Schemas
return UpdateSchema(@event, headers, s => SchemaEventDispatcher.Dispatch(@event, s));
}
protected Task On(SchemaFieldsReordered @event, EnvelopeHeaders headers)
{
return UpdateSchema(@event, headers, s => SchemaEventDispatcher.Dispatch(@event, s));
}
protected Task On(SchemaUpdated @event, EnvelopeHeaders headers)
{
return UpdateSchema(@event, headers, s => SchemaEventDispatcher.Dispatch(@event, s));

2
src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs

@ -72,7 +72,7 @@ namespace Squidex.Controllers.Api.Schemas
/// 400 => Schema field ids do not cover the fields of the schema.
/// 404 => Schema or app not found.
/// </returns>
[HttpPost]
[HttpPut]
[Route("apps/{app}/schemas/{name}/fields/ordering")]
[ProducesResponseType(typeof(ErrorDto), 400)]
public async Task<IActionResult> PutFieldOrdering(string app, string name, [FromBody] ReorderFields request)

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

@ -8,6 +8,7 @@
import { ApplicationRef, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { DndModule } from 'ng2-dnd';
import { AppComponent } from './app.component';
@ -49,6 +50,7 @@ export function configUserReport() {
imports: [
BrowserModule,
BrowserAnimationsModule,
DndModule.forRoot(),
SqxFrameworkModule.forRoot(),
SqxSharedModule.forRoot(),
SqxShellModule,

5
src/Squidex/app/features/schemas/module.ts

@ -7,6 +7,7 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DndModule } from 'ng2-dnd';
import {
HelpComponent,
@ -16,6 +17,8 @@ import {
SqxSharedModule
} from 'shared';
import { SortedDirective } from './utils/sorted.directive';
import {
FieldComponent,
BooleanUIComponent,
@ -74,6 +77,7 @@ const routes: Routes = [
imports: [
SqxFrameworkModule,
SqxSharedModule,
DndModule,
RouterModule.forChild(routes)
],
declarations: [
@ -92,6 +96,7 @@ const routes: Routes = [
SchemaFormComponent,
SchemaPageComponent,
SchemasPageComponent,
SortedDirective,
StringUIComponent,
StringValidationComponent
]

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

@ -36,8 +36,8 @@
</div>
<div class="panel-main">
<div class="panel-content panel-content-scroll">
<div *ngFor="let field of schemaFields">
<div class="panel-content panel-content-scroll" dnd-sortable-container [sortableData]="schemaFields.mutableValues">
<div *ngFor="let field of schemaFields; let i = index" dnd-sortable [sortableIndex]="i" (sorted)="sortFields($event)">
<sqx-field [field]="field"
(disabling)="disableField(field)"
(deleting)="deleteField(field)"

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

@ -28,4 +28,8 @@
background: transparent;
vertical-align: baseline;
}
}
.dnd-sortable-drag {
border: 0;
}

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

@ -176,6 +176,18 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit {
});
}
public sortFields(fields: FieldDto[]) {
this.updateFields(ImmutableArray.of(fields));
this.appName()
.switchMap(app => this.schemasService.putFieldOrdering(app, this.schemaName, fields.map(t => t.fieldId), this.version)).retry(2)
.subscribe(() => {
this.updateFields(ImmutableArray.of(fields));
}, error => {
this.notifyError(error);
});
}
public saveField(field: FieldDto, newField: FieldDto) {
const request = new UpdateFieldDto(newField.properties);

39
src/Squidex/app/features/schemas/utils/sorted.directive.ts

@ -0,0 +1,39 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Directive, EventEmitter, Output } from '@angular/core';
import {
SortableComponent,
SortableContainer,
DragDropSortableService
} from 'ng2-dnd';
@Directive({
selector: '[sorted]'
})
export class SortedDirective {
@Output()
public sorted = new EventEmitter<Array<any>>();
constructor(
sortableComponent: SortableComponent,
sortableContainer: SortableContainer,
sortableDragDropService: DragDropSortableService
) {
const oldCallback = sortableComponent._onDropCallback.bind(sortableComponent);
sortableComponent._onDropCallback = (event: Event) => {
oldCallback(event);
if (sortableDragDropService.isDragged) {
this.sorted.emit(sortableContainer.sortableData);
}
};
}
}

6
src/Squidex/app/framework/utils/immutable-array.spec.ts

@ -154,6 +154,12 @@ describe('ImmutableArray', () => {
expect(array_2.values).toEqual([1, 2, 3, 4]);
});
it('should provide mutable values', () => {
const array_1 = ImmutableArray.of([3, 1, 4, 2]);
expect(array_1.mutableValues).toBe(array_1.mutableValues);
});
it('should iterate over array items', () => {
const array_1 = ImmutableArray.of([3, 1, 4, 2]);

4
src/Squidex/app/framework/utils/immutable-array.ts

@ -23,6 +23,10 @@ export class ImmutableArray<T> implements Iterable<T> {
return [...this.items];
}
public get mutableValues(): T[] {
return this.items;
}
private constructor(items: T[]) {
this.items = items;
}

16
src/Squidex/app/shared/services/schemas.service.spec.ts

@ -273,6 +273,22 @@ describe('SchemasService', () => {
authService.verifyAll();
});
it('should make put request to update field ordering', () => {
const dto = [1, 2, 3]
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/fields/ordering', It.isAny(), version))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.putFieldOrdering('my-app', 'my-schema', dto, version);
authService.verifyAll();
});
it('should make put request to publish schema', () => {
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/publish', It.isAny(), version))
.returns(() => Observable.of(

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

@ -327,6 +327,13 @@ export class SchemasService {
.catchError('Failed to update schema. Please reload.');
}
public putFieldOrdering(appName: string, schemaName: string, dto: number[], version: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/ordering`);
return this.authService.authPut(url, { fieldIds: dto }, version)
.catchError('Failed to reorder fields. Please reload.');
}
public publishSchema(appName: string, schemaName: string, version: Version): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/publish`);

3
src/Squidex/app/theme/theme.scss

@ -6,6 +6,9 @@
// Pikaday
@import './../../node_modules/pikaday/css/pikaday.css';
// Drag and Drop
@import './../../node_modules/ng2-dnd/bundles/style.css';
// Bootstrap Overrides
@import '_bootstrap.scss';

1
src/Squidex/package.json

@ -29,6 +29,7 @@
"core-js": "2.4.1",
"moment": "2.18.1",
"mousetrap": "1.6.1",
"ng2-dnd": "^4.0.2",
"oidc-client": "1.3.0",
"pikaday": "1.5.1",
"redoc": "1.12.1",

Loading…
Cancel
Save