mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
33 changed files with 401 additions and 161 deletions
@ -0,0 +1,19 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
|
||||
|
namespace Squidex.Web |
||||
|
{ |
||||
|
public class ApiPermissionOrAnonymousAttribute : ApiPermissionAttribute, IAllowAnonymous |
||||
|
{ |
||||
|
public ApiPermissionOrAnonymousAttribute(params string[] ids) |
||||
|
: base(ids) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
<sqx-list-view [isLoaded]="isLoaded"> |
||||
|
<ng-container content> |
||||
|
<div #chartContainer></div> |
||||
|
</ng-container> |
||||
|
</sqx-list-view> |
||||
@ -0,0 +1,3 @@ |
|||||
|
div { |
||||
|
height: 500px; |
||||
|
} |
||||
@ -0,0 +1,151 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core'; |
||||
|
import { ResourceLoaderService, WorkflowDto } from '@app/shared'; |
||||
|
|
||||
|
declare var vis: any; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'sqx-workflow-diagram', |
||||
|
styleUrls: ['./workflow-diagram.component.scss'], |
||||
|
templateUrl: './workflow-diagram.component.html' |
||||
|
}) |
||||
|
export class WorkflowDiagramComponent implements AfterViewInit, OnDestroy, OnChanges { |
||||
|
private network: any; |
||||
|
|
||||
|
@ViewChild('chartContainer', { static: false }) |
||||
|
public chartContainer: ElementRef; |
||||
|
|
||||
|
@Input() |
||||
|
public workflow: WorkflowDto; |
||||
|
|
||||
|
public isLoaded = false; |
||||
|
|
||||
|
constructor( |
||||
|
private readonly resourceLoader: ResourceLoaderService |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public ngOnDestroy() { |
||||
|
this.network?.destroy(); |
||||
|
} |
||||
|
|
||||
|
public ngOnChanges() { |
||||
|
this.updateNetwork(); |
||||
|
} |
||||
|
|
||||
|
public ngAfterViewInit() { |
||||
|
this.updateNetwork(); |
||||
|
} |
||||
|
|
||||
|
private updateNetwork() { |
||||
|
if (this.chartContainer?.nativeElement && this.workflow) { |
||||
|
this.resourceLoader.loadLocalScript('dependencies/vis-network.min.js') |
||||
|
.then(() => { |
||||
|
this.network?.destroy(); |
||||
|
|
||||
|
const nodes = new vis.DataSet(); |
||||
|
|
||||
|
for (const step of this.workflow.steps) { |
||||
|
let label = `<b>${step.name}</b>`; |
||||
|
|
||||
|
if (step.noUpdate) { |
||||
|
label += `\nPrevent updates`; |
||||
|
|
||||
|
if (step.noUpdateExpression) { |
||||
|
label += `\nwhen (${step.noUpdateExpression})`; |
||||
|
} |
||||
|
|
||||
|
if (step.noUpdateRoles && step.noUpdateRoles.length > 0) { |
||||
|
label += `\nfor ${step.noUpdateRoles.join(', ')}`; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (step.name === 'Published') { |
||||
|
label += `\nAvailable in the API`; |
||||
|
} |
||||
|
|
||||
|
const node: any = { id: step.name, label, color: step.color }; |
||||
|
|
||||
|
nodes.add(node); |
||||
|
} |
||||
|
|
||||
|
if (this.workflow.initial) { |
||||
|
nodes.add({ id: 0, color: '#000', label: 'Start', shape: 'dot', size: 3 }); |
||||
|
} |
||||
|
|
||||
|
const edges = new vis.DataSet(); |
||||
|
|
||||
|
for (const transition of this.workflow.transitions) { |
||||
|
let label = ''; |
||||
|
|
||||
|
if (transition.expression) { |
||||
|
label += `\nwhen (${transition.expression})`; |
||||
|
} |
||||
|
|
||||
|
if (transition.roles && transition.roles.length > 0) { |
||||
|
label += `\nfor ${transition.roles.join(', ')}`; |
||||
|
} |
||||
|
|
||||
|
const edge: any = { ...transition, label }; |
||||
|
|
||||
|
edges.add(edge); |
||||
|
} |
||||
|
|
||||
|
if (this.workflow.initial) { |
||||
|
edges.add({ from: 0, to: this.workflow.initial }); |
||||
|
} |
||||
|
|
||||
|
this.network = new vis.Network(this.chartContainer.nativeElement, { edges, nodes }, GRAPH_OPTIONS); |
||||
|
this.network.stabilize(); |
||||
|
this.network.fit(); |
||||
|
|
||||
|
this.isLoaded = true; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const GRAPH_OPTIONS = { |
||||
|
nodes: { |
||||
|
borderWidth: 2, |
||||
|
font: { |
||||
|
multi: true, align: 'left', |
||||
|
ital: { |
||||
|
size: 16 |
||||
|
}, |
||||
|
bold: { |
||||
|
size: 20 |
||||
|
}, |
||||
|
size: 16 |
||||
|
}, |
||||
|
shape: 'dot', |
||||
|
shadow: true |
||||
|
}, |
||||
|
edges: { |
||||
|
arrows: 'to', |
||||
|
font: { |
||||
|
multi: true, |
||||
|
ital: { |
||||
|
size: 16 |
||||
|
}, |
||||
|
size: 16 |
||||
|
}, |
||||
|
color: 'gray' |
||||
|
}, |
||||
|
layout: { |
||||
|
randomSeed: 2 |
||||
|
}, |
||||
|
physics: { |
||||
|
enabled: false, |
||||
|
repulsion: { |
||||
|
nodeDistance: 300 |
||||
|
}, |
||||
|
solver: 'repulsion' |
||||
|
} |
||||
|
}; |
||||
Loading…
Reference in new issue