Browse Source

COntinued with UI.

pull/372/head
Sebastian Stehle 7 years ago
parent
commit
ee47bd22c6
  1. 52
      src/Squidex/app-config/webpack.config.js
  2. 24
      src/Squidex/app/features/settings/pages/workflows/workflow-step.component.html
  3. 11
      src/Squidex/app/features/settings/pages/workflows/workflow-step.component.scss
  4. 9
      src/Squidex/app/features/settings/pages/workflows/workflow-step.component.ts
  5. 8
      src/Squidex/app/features/settings/pages/workflows/workflows-page.component.html
  6. 31
      src/Squidex/app/features/settings/pages/workflows/workflows-page.component.ts
  7. 12
      src/Squidex/app/framework/angular/forms/color-picker.component.html
  8. 47
      src/Squidex/app/framework/angular/forms/color-picker.component.ts
  9. 10
      src/Squidex/app/framework/angular/forms/dropdown.component.html
  10. 7
      src/Squidex/app/framework/angular/forms/dropdown.component.scss
  11. 15
      src/Squidex/app/framework/angular/forms/dropdown.component.ts
  12. 24
      src/Squidex/app/framework/angular/panel.component.ts
  13. 12
      src/Squidex/app/shared/services/workflows.service.ts

52
src/Squidex/app-config/webpack.config.js

@ -33,7 +33,7 @@ module.exports = function(env) {
const isProduction = env && env.production;
const isTests = env && env.target === 'tests';
const isCoverage = env && env.coverage;
const isJit = env && env.jit;
const isAot = isProduction;
const config = {
mode: isProduction ? 'production' : 'development',
@ -56,7 +56,7 @@ module.exports = function(env) {
*
* See: https://webpack.js.org/configuration/resolve/#resolve-extensions
*/
extensions: ['.js', '.mjs', '.ts', '.css', '.scss'],
extensions: ['.ts', '.js', '.mjs', '.css', '.scss'],
modules: [
root('app'),
root('app', 'theme'),
@ -181,8 +181,6 @@ module.exports = function(env) {
}
};
console.log(JSON.stringify(config, null, 2));
if (!isTests) {
/**
* The entry point for the bundle. Our Angular app.
@ -258,6 +256,15 @@ module.exports = function(env) {
waitForLinting: isProduction
})
);
config.plugins.push(
new plugins.NgToolsWebpack.AngularCompilerPlugin({
entryModule: 'app/app.module#AppModule',
sourceMap: !isProduction,
skipSourceGeneration: !isAot,
tsConfigPath: './tsconfig.json'
})
);
}
if (isProduction) {
@ -284,14 +291,8 @@ module.exports = function(env) {
};
}
if (!isCoverage) {
config.module.rules.push({
test: /\.ts$/,
use: [{
loader: 'awesome-typescript-loader', options: { useCache: true, useBabel: true }
}]
})
} else {
if (isCoverage) {
// Do not instrument tests.
config.module.rules.push({
test: /\.ts$/,
use: [{
@ -300,7 +301,7 @@ module.exports = function(env) {
include: [/\.(e2e|spec)\.ts$/],
});
// Use instrument loader for all normal builds.
// Use instrument loader for all normal files.
config.module.rules.push({
test: /\.ts$/,
use: [{
@ -310,6 +311,13 @@ module.exports = function(env) {
}],
exclude: [/\.(e2e|spec)\.ts$/]
});
} else {
config.module.rules.push({
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [{
loader: plugins.NgToolsWebpack.NgToolsLoader
}]
})
}
if (isProduction) {
@ -349,23 +357,5 @@ module.exports = function(env) {
});
}
if (!isJit) {
config.module.rules.push({
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [{
loader: '@ngtools/webpack'
}]
});
config.plugins.push(
new plugins.NgToolsWebpack.AngularCompilerPlugin({
entryModule: 'app/app.module#AppModule',
sourceMap: !isProduction,
skipSourceGeneration: false,
tsConfigPath: './tsconfig.json'
})
);
}
return config;
};

24
src/Squidex/app/features/settings/pages/workflows/workflow-step.component.html

@ -2,8 +2,10 @@
<div class="row no-gutters">
<div class="col-auto color pr-2">
<sqx-color-picker mode="Circle"
[ngModelOptions]="onBlur"
[ngModel]="step.color"
(ngModelChange)="changeColor($event)">
(ngModelChange)="changeColor($event)"
[disabled]="step.isLocked">
</sqx-color-picker>
</div>
<div class="col">
@ -20,18 +22,22 @@
</div>
</div>
<div class="row transition no-gutters">
<div class="row transition no-gutters" *ngFor="let transition of transitions">
<div class="col-auto">
<i class="icon-arrow-right text-decent"></i>
</div>
<div class="col-3 pl-2">
<div class="color-circle" [style.background]="'red'"></div> In Progress
<div class="transition-to">
<div class="color-circle" [style.background]="transition.step.color"></div> {{transition.to}}
</div>
</div>
<div class="col pl-2">
<input class="form-control" placeholder="Expression" />
<button class="btn btn-block btn-outline-secondary dashed">
Add Expression
</button>
</div>
<div class="col-auto pl-2">
<button type="button" class="btn btn-text-danger" (click)="remove.emit()">
<button type="button" class="btn btn-text-danger" (click)="transitionRemove.emit(transition)">
<i class="icon-bin2"></i>
</button>
</div>
@ -42,17 +48,15 @@
<i class="icon-arrow-right text-decent"></i>
</div>
<div class="col-3 pl-2">
<sqx-dropdown [items]="openSteps">
<sqx-dropdown [items]="openSteps" [(ngModel)]="openStep">
<ng-template let-target="$implicit">
<span class="autocomplete-user">
<div class="color-circle" [style.background]="target.color"></div> {{target.name}}
</span>
</ng-template>
</sqx-dropdown>
</div>
<div class="col pl-2">
<button class="btn btn-success">
Add Transition
<button class="btn btn-outline-secondary" (click)="transitionAdd.emit(openStep)">
<i class="icon-plus"></i>
</button>
</div>
</div>

11
src/Squidex/app/features/settings/pages/workflows/workflow-step.component.scss

@ -12,6 +12,10 @@
display: inline-block;
}
.dashed {
border-style: dashed;
}
.transition {
& {
padding-left: 1rem;
@ -19,6 +23,13 @@
margin-bottom: .5rem;
line-height: 2rem;
}
&-to {
padding: .5rem .75rem;
background: transparent;
border: 1px solid transparent;
line-height: 1.2rem;
}
}
.step {

9
src/Squidex/app/features/settings/pages/workflows/workflow-step.component.ts

@ -27,6 +27,9 @@ export class WorkflowStepComponent implements OnChanges {
@Input()
public step: WorkflowStep;
@Output()
public transitionAdd = new EventEmitter<WorkflowStep>();
@Output()
public transitionRemove = new EventEmitter<WorkflowTransition>();
@ -39,13 +42,17 @@ export class WorkflowStepComponent implements OnChanges {
@Output()
public remove = new EventEmitter();
public onBlur = { updateOn: 'blur' };
public openSteps: WorkflowStep[];
public openStep: WorkflowStep;
public transitions: WorkflowTransitionView[];
public ngOnChanges(changes: SimpleChanges) {
if (changes['workflow'] || changes['step']) {
if (changes['workflow'] || changes['step'] || false) {
this.openSteps = this.workflow.getOpenSteps(this.step);
this.openStep = this.openSteps[0];
this.transitions = this.workflow.getTransitions(this.step);
}

8
src/Squidex/app/features/settings/pages/workflows/workflows-page.component.html

@ -20,12 +20,14 @@
</ng-container>
<ng-container content>
<sqx-workflow-step *ngFor="let step of workflow.steps"
<sqx-workflow-step *ngFor="let step of workflow.steps; trackBy: trackByStep"
[workflow]="workflow"
[step]="step"
(update)="updateStep(step, $event)"
(rename)="renameStep(step, $event)"
(remove)="removeStep(step)">
(remove)="removeStep(step)"
(transitionAdd)="addTransiton(step, $event)"
(transitionRemove)="removeTransition(step, $event)"
(update)="updateStep(step, $event)">
</sqx-workflow-step>
<button class="btn btn-success" (click)="addStep()">

31
src/Squidex/app/features/settings/pages/workflows/workflows-page.component.ts

@ -5,12 +5,13 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import {
WorkflowDto,
WorkflowStep,
WorkflowStepValues
WorkflowStepValues,
WorkflowTransition
} from '@app/shared';
@Component({
@ -18,8 +19,12 @@ import {
styleUrls: ['./workflows-page.component.scss'],
templateUrl: './workflows-page.component.html'
})
export class WorkflowsPageComponent {
public workflow = new WorkflowDto().setStep('Published', { color: 'green' });
export class WorkflowsPageComponent implements OnInit {
public workflow: WorkflowDto;
public ngOnInit() {
this.workflow = new WorkflowDto().setStep('Published', { color: 'green', isLocked: true });
}
public reload() {
return;
@ -33,16 +38,28 @@ export class WorkflowsPageComponent {
this.workflow = this.workflow.setStep(`Step${this.workflow.steps.length + 1}`, {});
}
public addTransiton(from: WorkflowStep, to: WorkflowStep) {
this.workflow = this.workflow.setTransition(from.name, to.name, {});
}
public removeTransition(from: WorkflowStep, transition: WorkflowTransition) {
this.workflow = this.workflow.removeTransition(from.name, transition.to);
}
public updateStep(step: WorkflowStep, values: WorkflowStepValues) {
// this.workflow = this.workflow.setStep(step.name, values);
this.workflow = this.workflow.setStep(step.name, values);
}
public renameStep(step: WorkflowStep, newName: string) {
// this.workflow = this.workflow.renameStep(step.name, newName);
this.workflow = this.workflow.renameStep(step.name, newName);
}
public removeStep(step: WorkflowStep) {
// this.workflow = this.workflow.removeStep(step.name);
this.workflow = this.workflow.removeStep(step.name);
}
public trackByStep(index: number, step: WorkflowStep) {
return step.name;
}
}

12
src/Squidex/app/framework/angular/forms/color-picker.component.html

@ -5,21 +5,23 @@
[style.color]="snapshot.foreground"
[placeholder]="placeholder"
[ngModel]="snapshot.value"
(ngModelChange)="writeValue($event)"
(focus)="modal.show()" (blur)="blur()" />
(ngModelChange)="updateValue($event)"
(focus)="focus()" (blur)="blur()" />
</ng-container>
<ng-template #circle>
<div class="circle" [style.background]="snapshot.value" (click)="modal.show()"></div>
<div class="circle" [style.background]="snapshot.value" (click)="focus()"></div>
</ng-template>
</span>
<div *sqxModalView="modal" [sqxModalTarget]="input" position="bottom-left">
<div *sqxModalView="modal" [sqxModalTarget]="input" position="bottom-left"
[style.height]="'228px'"
[style.width]="'130px'">
<div [style.background]="snapshot.value"
[cpToggle]="true"
[cpDialogDisplay]="'inline'"
[cpCancelButton]="false"
[colorPicker]="snapshot.value"
(colorPickerChange)="writeValue($event)">
(colorPickerChange)="updateValue($event)">
</div>
</div>

47
src/Squidex/app/framework/angular/forms/color-picker.component.ts

@ -32,19 +32,41 @@ interface State {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ColorPickerComponent extends StatefulControlComponent<State, string> {
private wasOpen = false;
@Input()
public placeholder = '';
@Input()
public mode: 'Input' | 'Circle' = 'Input';
@Input()
public set disabled(value: boolean) {
super.setDisabledState(value);
}
public modal = new ModalModel();
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, { foreground: 'black' });
this.modal.isOpen.subscribe(open => {
if (open) {
this.wasOpen = true;
} else {
if (this.wasOpen) {
this.callTouched();
}
this.wasOpen = false;
}
});
}
public writeValue(obj: any) {
const previousColor = this.snapshot.value;
if (previousColor !== obj) {
let foreground = 'black';
if (MathHelper.toLuminance(MathHelper.parseColor(obj)!) < .5) {
@ -52,11 +74,34 @@ export class ColorPickerComponent extends StatefulControlComponent<State, string
}
this.next(s => ({ ...s, value: obj, foreground }));
}
}
public focus() {
if (this.snapshot.isDisabled) {
return;
}
this.callChange(obj);
this.modal.show();
}
public blur() {
if (this.snapshot.isDisabled) {
return;
}
this.callTouched();
}
public updateValue(value: string) {
if (this.snapshot.isDisabled) {
return;
}
if (this.snapshot.value !== value) {
this.callChange(value);
this.writeValue(value);
}
}
}

10
src/Squidex/app/framework/angular/forms/dropdown.component.html

@ -6,20 +6,20 @@
autocapitalize="off">
<div class="control-dropdown-item" *ngIf="snapshot.selectedItem">
<ng-container *ngIf="!selectionTemplate">{{snapshot.selectedItem}}</ng-container>
<ng-container *ngIf="!templateSelection">{{snapshot.selectedItem}}</ng-container>
<ng-template *ngIf="selectionTemplate" [sqxTemplateWrapper]="selectionTemplate" [item]="snapshot.selectedItem"></ng-template>
<ng-template *ngIf="templateSelection" [sqxTemplateWrapper]="templateSelection" [item]="snapshot.selectedItem"></ng-template>
</div>
<i class="icon-caret-down"></i>
</div>
<div class="items-container">
<div class="control-dropdown" #container *sqxModalView="dropdown" [sqxModalTarget]="input" position="bottomLeft">
<div class="control-dropdown" #container *sqxModalView="dropdown" [sqxModalTarget]="input" position="bottom-left">
<div *ngFor="let item of items; let i = index;" class="control-dropdown-item control-dropdown-item-selectable" [class.active]="i === snapshot.selectedIndex" (mousedown)="selectIndexAndClose(i)" [sqxScrollActive]="i === snapshot.selectedIndex" [container]="container">
<ng-container *ngIf="!itemTemplate">{{item}}</ng-container>
<ng-container *ngIf="!templateItem">{{item}}</ng-container>
<ng-template *ngIf="itemTemplate" [sqxTemplateWrapper]="itemTemplate" [item]="item" [index]="i"></ng-template>
<ng-template *ngIf="templateItem" [sqxTemplateWrapper]="templateItem" [item]="item" [index]="i"></ng-template>
</div>
</div>
</div>

7
src/Squidex/app/framework/angular/forms/dropdown.component.scss

@ -26,13 +26,18 @@ $color-input-disabled: #eef1f4;
.control-dropdown-item {
@include absolute(0, 1rem, 0, 0);
pointer-events: none;
position: absolute;
line-height: 1.2rem;
}
.icon-caret-down {
@include absolute(30%, .4rem, auto, auto);
cursor: pointer;
font-size: .9rem;
font-weight: normal;
pointer-events: none;
}
.form-control {
cursor: default;
}
}

15
src/Squidex/app/framework/angular/forms/dropdown.component.ts

@ -35,9 +35,8 @@ export class DropdownComponent extends StatefulControlComponent<State, any[]> im
public dropdown = new ModalModel();
public selectionTemplate: TemplateRef<any>;
public itemTemplate: TemplateRef<any>;
public templateSelection: TemplateRef<any>;
public templateItem: TemplateRef<any>;
constructor(changeDetector: ChangeDetectorRef) {
super(changeDetector, {
@ -48,16 +47,20 @@ export class DropdownComponent extends StatefulControlComponent<State, any[]> im
public ngAfterContentInit() {
if (this.templates.length === 1) {
this.itemTemplate = this.selectionTemplate = this.templates.first;
this.templateItem = this.templateSelection = this.templates.first;
} else {
this.templates.forEach(template => {
if (template.name === 'selection') {
this.selectionTemplate = template;
this.templateSelection = template;
} else {
this.itemTemplate = template;
this.templateItem = template;
}
});
}
if (this.templateItem) {
this.detectChanges();
}
}
public writeValue(obj: any) {

24
src/Squidex/app/framework/angular/panel.component.ts

@ -89,17 +89,25 @@ export class PanelComponent implements AfterViewInit, OnDestroy, OnInit {
if (this.styleWidth !== size) {
this.styleWidth = size;
this.renderer.setStyle(this.panel.nativeElement, 'width', size);
this.renderer.setStyle(this.panel.nativeElement, 'minWidth', this.minWidth);
this.renderWidth = this.panel.nativeElement.offsetWidth;
const element = this.panel ? this.panel.nativeElement : undefined;
if (element) {
this.renderer.setStyle(element, 'width', size);
this.renderer.setStyle(element, 'minWidth', this.minWidth);
this.renderWidth = element.offsetWidth;
}
}
}
public arrange(left: any, layer: any) {
this.renderer.setStyle(this.panel.nativeElement, 'top', '0px');
this.renderer.setStyle(this.panel.nativeElement, 'left', left);
this.renderer.setStyle(this.panel.nativeElement, 'bottom', '0px');
this.renderer.setStyle(this.panel.nativeElement, 'position', 'absolute');
this.renderer.setStyle(this.panel.nativeElement, 'z-index', layer);
const element = this.panel ? this.panel.nativeElement : undefined;
if (element) {
this.renderer.setStyle(element, 'top', '0px');
this.renderer.setStyle(element, 'left', left);
this.renderer.setStyle(element, 'bottom', '0px');
this.renderer.setStyle(element, 'position', 'absolute');
this.renderer.setStyle(element, 'z-index', layer);
}
}
}

12
src/Squidex/app/shared/services/workflows.service.ts

@ -5,7 +5,11 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Model, ResourceLinks } from '@app/framework';
import {
compareStringsAsc,
Model,
ResourceLinks
} from '@app/framework';
export class WorkflowDto extends Model<WorkflowDto> {
public readonly _links: ResourceLinks;
@ -20,8 +24,12 @@ export class WorkflowDto extends Model<WorkflowDto> {
this._links = links;
}
public onCloned() {
this.steps.sort((a, b) => compareStringsAsc(a.name, b.name));
}
public getOpenSteps(step: WorkflowStep) {
return this.steps.filter(x => !this.transitions.find(y => y.from === step.name && y.to === x.name));
return this.steps.filter(x => x.name !== step.name && !this.transitions.find(y => y.from === step.name && y.to === x.name));
}
public getTransitions(step: WorkflowStep): WorkflowTransitionView[] {

Loading…
Cancel
Save