diff --git a/package.json b/package.json index 77139b9cfa..79af4fb0aa 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,10 @@ "rxjs": "~6.6.7", "showdown": "^2.0.3", "tslib": "^2.0.0", - "zone.js": "~0.11.4" + "zone.js": "~0.11.4", + "panzoom": "~9.4.3", + "@netgrif/petriflow.svg": "~1.0.0", + "@netgrif/petri.svg": "~1.0.0" }, "devDependencies": { "@angular-devkit/build-angular": "~13.3.1", diff --git a/projects/netgrif-components-core/src/assets/i18n/de.json b/projects/netgrif-components-core/src/assets/i18n/de.json index 8f3e2530da..aa02de2a79 100644 --- a/projects/netgrif-components-core/src/assets/i18n/de.json +++ b/projects/netgrif-components-core/src/assets/i18n/de.json @@ -256,7 +256,8 @@ "maxFilesSizeExceeded": "Die maximale Größe der hochgeladenen Dateien wird überschritten: ", "notSelectedUser": "Es wurde kein Benutzer ausgewählt", "userAssigned": "Benutzer {{userName}} wurde zugewiesen", - "userListAssigned": "Ausgewählte Benutzer {{userNames}} wurden zugewiesen" + "userListAssigned": "Ausgewählte Benutzer {{userNames}} wurden zugewiesen", + "caseNetGetFailed": "Das Abrufen des Fallnetzes ist fehlgeschlagen" }, "values": { "boolean": { diff --git a/projects/netgrif-components-core/src/assets/i18n/en.json b/projects/netgrif-components-core/src/assets/i18n/en.json index d0814f3cfc..b7bc4651a4 100644 --- a/projects/netgrif-components-core/src/assets/i18n/en.json +++ b/projects/netgrif-components-core/src/assets/i18n/en.json @@ -256,7 +256,8 @@ "maxFilesSizeExceeded": "The maximum size of uploaded files is exceeded: ", "notSelectedUser": "No user has been selected", "userAssigned": "User {{userName}} was assigned", - "userListAssigned": "Selected users {{userNames}} were assigned" + "userListAssigned": "Selected users {{userNames}} were assigned", + "caseNetGetFailed": "Getting case net failed" }, "values": { "boolean": { diff --git a/projects/netgrif-components-core/src/assets/i18n/sk.json b/projects/netgrif-components-core/src/assets/i18n/sk.json index 6cc671b42f..ae93e0ae3e 100644 --- a/projects/netgrif-components-core/src/assets/i18n/sk.json +++ b/projects/netgrif-components-core/src/assets/i18n/sk.json @@ -256,7 +256,8 @@ "maxFilesSizeExceeded": "Je presiahnutá maximálna veľkosť nahrávaných súborov: ", "notSelectedUser": "Nebol vybraný žiadny používateľ", "userAssigned": "Používateľ {{userName}} bol pridelený", - "userListAssigned": "Vybraní používatelia {{userNames}} boli pridelení" + "userListAssigned": "Vybraní používatelia {{userNames}} boli pridelení", + "caseNetGetFailed": "Načítanie siete podľa prípadu zlyhalo" }, "values": { "boolean": { diff --git a/projects/netgrif-components-core/src/lib/data-fields/case-ref-field/abstract-case-ref-field.component.ts b/projects/netgrif-components-core/src/lib/data-fields/case-ref-field/abstract-case-ref-field.component.ts new file mode 100644 index 0000000000..27434c1268 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/data-fields/case-ref-field/abstract-case-ref-field.component.ts @@ -0,0 +1,261 @@ +import {AfterViewInit, Component, Inject, Input, OnDestroy, Optional} from '@angular/core'; +import { + PetriflowArc, + PetriflowCanvasConfigurationService, + PetriflowCanvasFactoryService, + PetriflowCanvasService, + PetriflowInhibitorArc, + PetriflowPlace, + PetriflowPlaceTransitionArc, PetriflowReadArc, + PetriflowResetArc, + PetriflowTransition, PetriflowTransitionPlaceArc +} from '@netgrif/petriflow.svg'; +import { + Arc, + InhibitorArc, Place, + ReadArc, + RegularPlaceTransitionArc, + RegularTransitionPlaceArc, + ResetArc +} from '@netgrif/petri.svg'; +import {CaseRefField} from './models/case-ref-field'; +import {PetriNetResourceService} from '../../resources/engine-endpoint/petri-net-resource.service'; +import {CaseResourceService} from '../../resources/engine-endpoint/case-resource.service'; +import {TransitionImport} from '../../resources/interface/transition-import'; +import {PlaceImport} from '../../resources/interface/place-import'; +import {ArcImport} from '../../resources/interface/arc-import'; +import {ArcType} from '../../resources/interface/arc-type'; +import {PetriNetImport} from '../../resources/interface/petri-net-import'; +import {LoggerService} from '../../logger/services/logger.service'; +import {SnackBarService} from '../../snack-bar/services/snack-bar.service'; +import {TranslateService} from '@ngx-translate/core'; +import {AbstractDataFieldComponent} from '../models/abstract-data-field-component'; +import {NAE_INFORM_ABOUT_INVALID_DATA} from '../models/invalid-data-policy-token'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'ncc-abstract-case-ref-field', + template: '' +}) +export abstract class AbstractCaseRefFieldComponent extends AbstractDataFieldComponent implements AfterViewInit, OnDestroy { + + @Input() public dataField: CaseRefField; + protected sub: Subscription; + + constructor(protected _petriflowCanvasService: PetriflowCanvasService, protected _petriflowFactoryService: PetriflowCanvasFactoryService, + protected _petriflowConfigService: PetriflowCanvasConfigurationService, protected _caseResourceService: CaseResourceService, + protected _petriNetResourceService: PetriNetResourceService, protected _log: LoggerService, protected _snackBar: SnackBarService, + protected _translate: TranslateService, @Optional() @Inject(NAE_INFORM_ABOUT_INVALID_DATA) informAboutInvalidData: boolean | null) { + super(informAboutInvalidData); + } + + ngAfterViewInit(): void { + this.sub = this.formControl.valueChanges.subscribe(value => { + if (value?.length > 0) { + this._petriNetResourceService.getNetByCaseId(value[0]).subscribe(net => { + this.createNet(net); + }, error => { + this._log.error('Getting net by Case ID failed in field ['+ this.dataField.stringId + ']', error); + this._snackBar.openErrorSnackBar(this._translate.instant('dataField.snackBar.caseNetGetFailed')); + }); + } + }); + } + + protected createNet(net: PetriNetImport) { + const trans: Array = []; + const places: Array = []; + const arcs: Array> = []; + let minX: number = Number.MAX_SAFE_INTEGER; + let minY: number = Number.MAX_SAFE_INTEGER; + net.transitions.forEach((value) => { + const t = this.createTransitions(value) + trans.push(t); + minX = Math.min(minX, value.position.x); + minY = Math.min(minY, value.position.y); + this.setEmptyEvents(t.canvasElement.element); + }) + net.places.forEach((value) => { + const p = this.createPlace(value) + places.push(p); + minX = Math.min(minX, value.position.x); + minY = Math.min(minY, value.position.y); + this.setEmptyEvents(p.canvasElement.element); + p.canvasElement.markingTokens.forEach(markingToken => { + this.setEmptyEvents(markingToken); + }); + }) + net.arcs.forEach((arc) => { + const a = this.createArcs(trans, places, arc, net) + arcs.push(a); + arc.breakpoints?.forEach(value => { + minX = Math.min(minX, value.x); + minY = Math.min(minY, value.y); + }); + this.setEmptyEvents(a.element.arcLine); + }); + trans.forEach(value => { + if (net.assignedTasks.includes(value.canvasElement.label.textContent)) { + value.select(); + } + if (this.isEnabled(value, places, arcs)) { + value.canvasElement.element.classList.add('svg-transition-enabled'); + value.canvasElement.element.setAttributeNS(null, 'fill', 'yellowgreen'); + value.canvasElement.element.setAttributeNS(null, 'stroke', 'green'); + } + }); + this._petriflowCanvasService.panzoom?.moveTo(-minX + 20, -minY + 20); + if (this.dataField.component?.properties?.lock === 'true') { + setTimeout(() => { + this._petriflowCanvasService.panzoom?.pause(); + }) + } + } + + protected createTransitions(value: TransitionImport): PetriflowTransition { + const transition = this._petriflowFactoryService.createTransition(new DOMPoint(value.position.x, value.position.y)); + transition.changeId(value.stringId); + this._petriflowConfigService.addTransitionEvents(transition); + return transition; + } + + protected createPlace(value: PlaceImport): PetriflowPlace { + const place = this._petriflowFactoryService.createPlace(value.tokens, new DOMPoint(value.position.x, value.position.y)); + place.changeId(value.stringId); + this._petriflowConfigService.addPlaceEvents(place); + return place; + } + + protected createArcs(trans: Array, places: Array, arc: ArcImport, net: PetriNetImport) { + let source: PetriflowPlace | PetriflowTransition = trans.find(value => value.canvasElement.label.textContent === arc.sourceId); + let destination: PetriflowPlace | PetriflowTransition; + let activable: boolean = false; + if (source === undefined) { + source = places.find(value => value.canvasElement.label.textContent === arc.sourceId); + destination = trans.find(value => value.canvasElement.label.textContent === arc.destinationId); + if (net.assignedTasks.includes(destination.canvasElement.label.textContent)) { + source.select(); + destination.select(); + activable = true; + } + } else { + destination = places.find(value => value.canvasElement.label.textContent === arc.destinationId); + if (net.finishedTasks.includes(source.canvasElement.label.textContent)) { + source.select(); + destination.select(); + activable = true; + } + } + if (source === undefined || destination === undefined) { + this._log.error("Can't find source or destination for arc [" + arc.importId + "]"); + } else { + const newArc: Arc = this.createArc(arc, source, destination); + const petriflowArc: PetriflowArc = this.createPetriflowArc(arc, newArc, source); + if (activable) { + petriflowArc.select(); + } + this._petriflowCanvasService.canvas.container.appendChild(newArc.container); + this._petriflowCanvasService.petriflowElementsCollection.arcs.push(petriflowArc); + return petriflowArc; + } + return undefined + } + + protected createArc(arc: ArcImport, source: PetriflowTransition | PetriflowPlace, destination: PetriflowPlace | PetriflowTransition) { + if (source instanceof PetriflowPlace) { + switch (arc.type) { + case ArcType.ARC: { + return this._petriflowFactoryService.createArc(RegularPlaceTransitionArc, source.canvasElement, destination.canvasElement, arc.breakpoints, arc.multiplicity); + } + case ArcType.RESET: { + return this._petriflowFactoryService.createArc(ResetArc, source.canvasElement, destination.canvasElement, arc.breakpoints, arc.multiplicity); + } + case ArcType.INHIBITOR: { + return this._petriflowFactoryService.createArc(InhibitorArc, source.canvasElement, destination.canvasElement, arc.breakpoints, arc.multiplicity); + } + case ArcType.READ: { + return this._petriflowFactoryService.createArc(ReadArc, source.canvasElement, destination.canvasElement, arc.breakpoints, arc.multiplicity); + } + default: { + return undefined; + } + } + } else if (arc.type === ArcType.ARC) { + return this._petriflowFactoryService.createArc(RegularTransitionPlaceArc, source.canvasElement, destination.canvasElement, arc.breakpoints, arc.multiplicity); + } else { + return undefined; + } + } + + protected createPetriflowArc(arc: ArcImport, newArc: Arc, source: PetriflowTransition | PetriflowPlace) { + if (source instanceof PetriflowPlace) { + switch (arc.type) { + case ArcType.ARC: { + return this._petriflowFactoryService.createArc(PetriflowPlaceTransitionArc, newArc); + } + case ArcType.RESET: { + return this._petriflowFactoryService.createArc(PetriflowResetArc, newArc); + } + case ArcType.INHIBITOR: { + return this._petriflowFactoryService.createArc(PetriflowInhibitorArc, newArc); + } + case ArcType.READ: { + return this._petriflowFactoryService.createArc(PetriflowReadArc, newArc); + } + default: { + return undefined; + } + } + } else if (arc.type === ArcType.ARC) { + return this._petriflowFactoryService.createArc(PetriflowTransitionPlaceArc, newArc); + } else { + return undefined; + } + } + + protected isEnabled(t: PetriflowTransition, places: Array, arcs: Array>): boolean { + const testMarking: Map = new Map(); + + for (const place of places) { + testMarking.set(place.canvasElement.id, place.canvasElement.tokensCount); + } + for (const arc of arcs) { + if (arc.element.end.id === t.canvasElement.id && (arc instanceof PetriflowInhibitorArc) && testMarking.get((arc.element.start as Place).id) >= parseInt(arc.element.multiplicity.data, 10)) { + return false; + } + } + for (const arc of arcs) { + if (arc.element.end.id === t.canvasElement.id && (arc instanceof PetriflowReadArc) && testMarking.get((arc.element.start as Place).id) < parseInt(arc.element.multiplicity.data, 10)) { + return false; + } + } + for (const arc of arcs) { + if (arc.element.end.id === t.canvasElement.id && arc instanceof PetriflowPlaceTransitionArc) { + const place = testMarking.get((arc.element.start as Place).id) + testMarking.set((arc.element.start as Place).id, place - parseInt(arc.element.multiplicity.data, 10)); + } + } + for (const place of testMarking.values()) { + if (place < 0) { + return false; + } + } + + return true; + } + + public getHeight() { + return (this.dataField.layout && this.dataField.layout.rows && this.dataField.layout.rows) > 1 ? + this.dataField.layout.rows * CaseRefField.FIELD_HEIGHT : CaseRefField.FIELD_HEIGHT; + } + + protected setEmptyEvents(svgElement: SVGElement) { + svgElement.onmouseenter = () => {}; + svgElement.onmouseleave = () => {}; + } + + ngOnDestroy() { + super.ngOnDestroy(); + this.sub.unsubscribe(); + } +} diff --git a/projects/netgrif-components-core/src/lib/data-fields/case-ref-field/models/case-ref-field.ts b/projects/netgrif-components-core/src/lib/data-fields/case-ref-field/models/case-ref-field.ts new file mode 100644 index 0000000000..bec9e38508 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/data-fields/case-ref-field/models/case-ref-field.ts @@ -0,0 +1,15 @@ +import {Behavior} from '../../models/behavior'; +import {Layout} from '../../models/layout'; +import {Validation} from '../../models/validation'; +import {Component} from '../../models/component'; +import {DataField} from '../../models/abstract-data-field'; + +export class CaseRefField extends DataField> { + + public static FIELD_HEIGHT: number = 75; + + constructor(stringId: string, title: string, value: Array, behavior: Behavior, placeholder?: string, + description?: string, layout?: Layout, validations?: Array, _component?: Component, parentTaskId?: string) { + super(stringId, title, value, behavior, placeholder, description, layout, validations, _component, parentTaskId); + } +} diff --git a/projects/netgrif-components-core/src/lib/data-fields/data-fields.module.ts b/projects/netgrif-components-core/src/lib/data-fields/data-fields.module.ts index 7e7e9a769a..2381bc4b3d 100644 --- a/projects/netgrif-components-core/src/lib/data-fields/data-fields.module.ts +++ b/projects/netgrif-components-core/src/lib/data-fields/data-fields.module.ts @@ -11,6 +11,7 @@ import {NgxMatDatetimePickerModule} from '@angular-material-components/datetime- import {NgxMatMomentModule} from '@angular-material-components/moment-adapter'; import {TranslateLibModule} from '../translate/translate-lib.module'; import {DateAdapter} from '@angular/material/core'; +import {PetriflowCanvasModule} from '@netgrif/petriflow.svg'; @NgModule({ imports: [ @@ -23,7 +24,8 @@ import {DateAdapter} from '@angular/material/core'; ReactiveFormsModule, NgxMatDatetimePickerModule, NgxMatMomentModule, - TranslateLibModule + TranslateLibModule, + PetriflowCanvasModule ], providers: [ {provide: DateAdapter, useClass: CustomDateAdapter} diff --git a/projects/netgrif-components-core/src/lib/data-fields/public-api.ts b/projects/netgrif-components-core/src/lib/data-fields/public-api.ts index 16157a3867..c83a948372 100644 --- a/projects/netgrif-components-core/src/lib/data-fields/public-api.ts +++ b/projects/netgrif-components-core/src/lib/data-fields/public-api.ts @@ -58,6 +58,7 @@ export * from './i18n-field/abstract-i18n-field.component'; export * from './i18n-field/i18n-text-field/abstract-i18n-text-field.component'; export * from './i18n-field/i18n-divider-field/abstract-i18n-divider-field.component'; export * from './i18n-field/abstract-i18n-errors.component'; +export * from './case-ref-field/abstract-case-ref-field.component'; export * from './user-list-field/abstract-user-list-field.component'; export * from './user-list-field/user-list-default-field/abstract-user-list-default-field.component'; export * from './task-ref-field/abstract-task-ref-field.component'; @@ -88,6 +89,7 @@ export * from './task-ref-field/model/task-ref-field'; export * from './enumeration-field/models/dynamic-enumeration-field'; export * from './filter-field/models/filter-field'; export * from './i18n-field/models/i18n-field'; +export * from './case-ref-field/models/case-ref-field'; export * from './user-list-field/models/user-list-field'; export * from './user-list-field/models/user-list-value'; export * from './case-ref-field/model/case-ref-field'; diff --git a/projects/netgrif-components-core/src/lib/resources/engine-endpoint/petri-net-resource.service.ts b/projects/netgrif-components-core/src/lib/resources/engine-endpoint/petri-net-resource.service.ts index 0e3f33f359..d30018d2cb 100644 --- a/projects/netgrif-components-core/src/lib/resources/engine-endpoint/petri-net-resource.service.ts +++ b/projects/netgrif-components-core/src/lib/resources/engine-endpoint/petri-net-resource.service.ts @@ -14,6 +14,7 @@ import {Page} from '../interface/page'; import {processMessageResponse} from '../../utility/process-message-response'; import {AbstractResourceService} from '../abstract-endpoint/abstract-resource.service'; import RolesAndPermissions from '../../process/rolesAndPermissions'; +import {PetriNetImport} from '../interface/petri-net-import'; @Injectable({ providedIn: 'root' @@ -181,4 +182,16 @@ export class PetriNetResourceService extends AbstractResourceService { return this._resourceProvider.delete$('petrinet/' + netId, this.SERVER_URL) .pipe(switchMap(processMessageResponse)); } + + /** + * get One Net by case ID + * + * **Request Type:** GET + * + * **Request URL:** {{baseUrl}}/api/petrinet/case/{id} + */ + public getNetByCaseId(caseId: string, params?: Params): Observable { + return this._resourceProvider.get$('petrinet/case/' + caseId, this.SERVER_URL, params) + .pipe(map(r => this.changeType(r, undefined))); + } } diff --git a/projects/netgrif-components-core/src/lib/resources/interface/arc-import.ts b/projects/netgrif-components-core/src/lib/resources/interface/arc-import.ts new file mode 100644 index 0000000000..7b653e06bd --- /dev/null +++ b/projects/netgrif-components-core/src/lib/resources/interface/arc-import.ts @@ -0,0 +1,12 @@ +import {Position} from './position'; +import {ArcType} from './arc-type'; + +export interface ArcImport { + destinationId: string; + sourceId: string; + importId: string; + multiplicity: number; + stringId: string; + breakpoints: Array; + type: ArcType; +} diff --git a/projects/netgrif-components-core/src/lib/resources/interface/arc-type.ts b/projects/netgrif-components-core/src/lib/resources/interface/arc-type.ts new file mode 100644 index 0000000000..68adc9cf57 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/resources/interface/arc-type.ts @@ -0,0 +1,6 @@ +export enum ArcType { + ARC = 'arc', + RESET = 'reset', + INHIBITOR = 'inhibitor', + READ = 'read' +} diff --git a/projects/netgrif-components-core/src/lib/resources/interface/petri-net-import.ts b/projects/netgrif-components-core/src/lib/resources/interface/petri-net-import.ts new file mode 100644 index 0000000000..1991637156 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/resources/interface/petri-net-import.ts @@ -0,0 +1,11 @@ +import {TransitionImport} from './transition-import'; +import {PlaceImport} from './place-import'; +import {ArcImport} from './arc-import'; + +export interface PetriNetImport { + transitions: Array; + places: Array; + arcs: Array; + assignedTasks: Array; + finishedTasks: Array; +} diff --git a/projects/netgrif-components-core/src/lib/resources/interface/place-import.ts b/projects/netgrif-components-core/src/lib/resources/interface/place-import.ts new file mode 100644 index 0000000000..9fc878d2a4 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/resources/interface/place-import.ts @@ -0,0 +1,10 @@ +import {Position} from './position'; + +export interface PlaceImport { + importId: string; + isStatic: boolean; + position: Position; + stringId: string; + title: object; + tokens: number; +} diff --git a/projects/netgrif-components-core/src/lib/resources/interface/position.ts b/projects/netgrif-components-core/src/lib/resources/interface/position.ts new file mode 100644 index 0000000000..f24a55f19b --- /dev/null +++ b/projects/netgrif-components-core/src/lib/resources/interface/position.ts @@ -0,0 +1,5 @@ + +export interface Position { + x: number; + y: number; +} diff --git a/projects/netgrif-components-core/src/lib/resources/interface/transition-import.ts b/projects/netgrif-components-core/src/lib/resources/interface/transition-import.ts new file mode 100644 index 0000000000..6afdeaa1f5 --- /dev/null +++ b/projects/netgrif-components-core/src/lib/resources/interface/transition-import.ts @@ -0,0 +1,8 @@ +import {Position} from './position'; + +export interface TransitionImport { + importId: string; + position: Position; + stringId: string; + title: object; +} diff --git a/projects/netgrif-components-core/src/lib/resources/public-api.ts b/projects/netgrif-components-core/src/lib/resources/public-api.ts index 5f539f1685..a2c23652b9 100644 --- a/projects/netgrif-components-core/src/lib/resources/public-api.ts +++ b/projects/netgrif-components-core/src/lib/resources/public-api.ts @@ -44,7 +44,12 @@ export * from './interface/user-resource'; export * from './interface/create-case-request-body'; export * from './interface/ldapGroupResponseBody'; export * from './interface/task-pair'; - +export * from './interface/arc-import'; +export * from './interface/place-import'; +export * from './interface/transition-import'; +export * from './interface/position'; +export * from './interface/petri-net-import'; +export * from './interface/arc-type'; export * from './types/nae-date-type'; /* ABSTRACTIONS */ diff --git a/projects/netgrif-components-core/src/lib/task-content/services/field-converter.service.ts b/projects/netgrif-components-core/src/lib/task-content/services/field-converter.service.ts index aec119d6ee..cb67448c8d 100644 --- a/projects/netgrif-components-core/src/lib/task-content/services/field-converter.service.ts +++ b/projects/netgrif-components-core/src/lib/task-content/services/field-converter.service.ts @@ -117,6 +117,9 @@ export class FieldConverterService { case FieldTypeResource.STRING_COLLECTION: return new StringCollectionField(item.stringId, item.name, item.value ? item.value : [], item.behavior, item.placeholder, item.description, item.layout, item.validations, item.component, item.parentTaskId); + case FieldTypeResource.CASE_REF: + return new CaseRefField(item.stringId, item.name, item.value ?? [], item.behavior, item.placeholder, + item.description, item.layout, item.validations, item.component); } } @@ -143,6 +146,8 @@ export class FieldConverterService { return FieldTypeResource.USER_LIST; } else if (item instanceof TaskRefField) { return FieldTypeResource.TASK_REF; + } else if (item instanceof CaseRefField) { + return FieldTypeResource.CASE_REF; } else if (item instanceof EnumerationField || item instanceof MultichoiceField) { return item.fieldType; } else if (item instanceof FilterField) { diff --git a/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.html b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.html new file mode 100644 index 0000000000..add89d36dd --- /dev/null +++ b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.scss b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.scss new file mode 100644 index 0000000000..7ce06c7f7a --- /dev/null +++ b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.scss @@ -0,0 +1,9 @@ +.outer { + display: flex; + width: 100%; + max-height: 100%; +} + +.canvas { + width: 100%; +} diff --git a/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.spec.ts b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.spec.ts new file mode 100644 index 0000000000..b2a6fdde79 --- /dev/null +++ b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.spec.ts @@ -0,0 +1,78 @@ +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import { + MaterialModule, + TranslateLibModule, + AuthenticationMethodService, + MockAuthenticationMethodService, + AuthenticationService, + MockAuthenticationService, + ConfigurationService, + TestConfigurationService, + CaseRefField, + PetriNetResourceService, + SnackBarModule +} from '@netgrif/components-core'; +import {CaseRefFieldComponent} from './case-ref-field.component'; +import {AngularResizeEventModule} from 'angular-resize-event'; +import {HttpClientTestingModule} from '@angular/common/http/testing'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {PetriflowCanvasModule} from '@netgrif/petriflow.svg'; +import {Component} from '@angular/core'; +import {of} from 'rxjs'; + +describe('CaseRefFieldComponent', () => { + let component: CaseRefFieldComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + MaterialModule, + AngularResizeEventModule, + TranslateLibModule, + HttpClientTestingModule, + NoopAnimationsModule, + PetriflowCanvasModule, + SnackBarModule + ], + providers: [ + {provide: AuthenticationMethodService, useClass: MockAuthenticationMethodService}, + {provide: AuthenticationService, useClass: MockAuthenticationService}, + {provide: ConfigurationService, useClass: TestConfigurationService}, + {provide: PetriNetResourceService, useClass: MyPetriNetResource}, + ], + declarations: [CaseRefFieldComponent] + }).compileComponents(); + fixture = TestBed.createComponent(TestWrapperComponent); + component = fixture.debugElement.children[0].componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + afterEach(() => { + TestBed.resetTestingModule(); + }); +}); + +@Component({ + selector: 'nc-test-wrapper', + template: '' +}) +class TestWrapperComponent { + field = new CaseRefField('', '', [], { + required: true, + }); +} + +class MyPetriNetResource { + public getNetByCaseId(caseId: string) { + return of({ + transitions: [], + places: [], + arcs: [] + }); + } +} diff --git a/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.ts b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.ts new file mode 100644 index 0000000000..b18545cbd1 --- /dev/null +++ b/projects/netgrif-components/src/lib/data-fields/case-ref-field/case-ref-field.component.ts @@ -0,0 +1,31 @@ +import {Component, Inject, Optional} from '@angular/core'; +import { + AbstractCaseRefFieldComponent, + CaseResourceService, + PetriNetResourceService, + LoggerService, + SnackBarService, NAE_INFORM_ABOUT_INVALID_DATA +} from '@netgrif/components-core'; +import { + PetriflowCanvasConfigurationService, + PetriflowCanvasFactoryService, + PetriflowCanvasService +} from '@netgrif/petriflow.svg'; +import {TranslateService} from '@ngx-translate/core'; + +@Component({ + selector: 'nc-case-ref-field', + templateUrl: './case-ref-field.component.html', + styleUrls: ['./case-ref-field.component.scss'] +}) +export class CaseRefFieldComponent extends AbstractCaseRefFieldComponent { + + constructor(protected _petriflowCanvasService: PetriflowCanvasService, protected _petriflowFactoryService: PetriflowCanvasFactoryService, + protected _petriflowConfigService: PetriflowCanvasConfigurationService, protected _caseResourceService: CaseResourceService, + protected _petriNetResourceService: PetriNetResourceService, protected _log: LoggerService, protected _snackBar: SnackBarService, + protected _translate: TranslateService, @Optional() @Inject(NAE_INFORM_ABOUT_INVALID_DATA) informAboutInvalidData: boolean | null){ + super(_petriflowCanvasService, _petriflowFactoryService, _petriflowConfigService, _caseResourceService, _petriNetResourceService, + _log, _snackBar, _translate, informAboutInvalidData); + } + +} diff --git a/projects/netgrif-components/src/lib/data-fields/data-field.theme.scss b/projects/netgrif-components/src/lib/data-fields/data-field.theme.scss index ba4735d179..503f06e92a 100644 --- a/projects/netgrif-components/src/lib/data-fields/data-field.theme.scss +++ b/projects/netgrif-components/src/lib/data-fields/data-field.theme.scss @@ -436,6 +436,27 @@ border-left: 1px solid $color-outline-enabled !important; border-right: 1px solid $color-outline-enabled !important; } + + .svg-inactive-stroke { + stroke: black !important; + } + + .svg-inactive-fill { + fill: black !important; + } + + .svg-active-stroke { + stroke: map-get($primary, A200) !important; + } + + .svg-active-fill { + fill: map-get($primary, A200) !important; + } + + .svg-transition-enabled { + stroke: green; + fill: yellowgreen; + } } .mat-calendar-arrow { diff --git a/projects/netgrif-components/src/lib/data-fields/data-fields.module.ts b/projects/netgrif-components/src/lib/data-fields/data-fields.module.ts index 6e7c16928c..12b82d8fab 100644 --- a/projects/netgrif-components/src/lib/data-fields/data-fields.module.ts +++ b/projects/netgrif-components/src/lib/data-fields/data-fields.module.ts @@ -4,7 +4,8 @@ import {FlexLayoutModule} from '@angular/flex-layout'; import { CovalentModule, CurrencyModule, - CustomDateAdapter, FrontActionModule, + CustomDateAdapter, + FrontActionModule, MaterialModule, TranslateLibModule, ComponentRegistryService @@ -76,6 +77,8 @@ import {I18nTextFieldComponent} from './i18n-field/i18n-text-field/i18n-text-fie import {EasymdeWrapperComponent} from './text-field/rich-textarea-field/easymde-wrapper/easymde-wrapper.component'; import {BrowserModule} from '@angular/platform-browser'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import { CaseRefFieldComponent } from './case-ref-field/case-ref-field.component'; +import {PetriflowCanvasModule} from '@netgrif/petriflow.svg'; import { MultichoiceAutocompleteFieldComponent } from './multichoice-field/multichoice-autocomplete-field/multichoice-autocomplete-field.component'; @@ -191,6 +194,7 @@ import {ComponentPortal} from "@angular/cdk/portal"; MultichoiceCaserefFieldComponent, EnumerationCaserefFieldComponent, StringCollectionDefaultFieldComponent, + CaseRefFieldComponent, SignaturePadFieldComponent, NumberDecimalFieldComponent ], @@ -219,7 +223,8 @@ import {ComponentPortal} from "@angular/cdk/portal"; BrowserAnimationsModule, DashboardComponentModule, RouterModule, - FrontActionModule + FrontActionModule. + PetriflowCanvasModule ], providers: [ {provide: DateAdapter, useClass: CustomDateAdapter} diff --git a/projects/netgrif-components/src/lib/task-content/field-component-resolver/field-component-resolver.component.html b/projects/netgrif-components/src/lib/task-content/field-component-resolver/field-component-resolver.component.html index e7bf9f6ba5..fd3ec3321f 100644 --- a/projects/netgrif-components/src/lib/task-content/field-component-resolver/field-component-resolver.component.html +++ b/projects/netgrif-components/src/lib/task-content/field-component-resolver/field-component-resolver.component.html @@ -1,5 +1,8 @@
+ + +
{{getDataGroupTitle()}}