UI: Implement rule chain page version control.
This commit is contained in:
parent
8382850d1a
commit
14023e4cc9
@ -27,6 +27,7 @@ import { AppState } from '@core/core.state';
|
|||||||
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
|
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
|
||||||
import { EntityId } from '@shared/models/id/entity-id';
|
import { EntityId } from '@shared/models/id/entity-id';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-entity-version-create',
|
selector: 'tb-entity-version-create',
|
||||||
@ -50,6 +51,9 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni
|
|||||||
@Input()
|
@Input()
|
||||||
onContentUpdated: () => void;
|
onContentUpdated: () => void;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
onBeforeCreateVersion: () => Observable<any>;
|
||||||
|
|
||||||
createVersionFormGroup: FormGroup;
|
createVersionFormGroup: FormGroup;
|
||||||
|
|
||||||
resultMessage: string;
|
resultMessage: string;
|
||||||
@ -78,25 +82,29 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni
|
|||||||
}
|
}
|
||||||
|
|
||||||
export(): void {
|
export(): void {
|
||||||
const request: SingleEntityVersionCreateRequest = {
|
const before = this.onBeforeCreateVersion ? this.onBeforeCreateVersion() : of(null);
|
||||||
entityId: this.entityId,
|
before.subscribe(() => {
|
||||||
branch: this.createVersionFormGroup.get('branch').value,
|
const request: SingleEntityVersionCreateRequest = {
|
||||||
versionName: this.createVersionFormGroup.get('versionName').value,
|
entityId: this.entityId,
|
||||||
config: {
|
branch: this.createVersionFormGroup.get('branch').value,
|
||||||
saveRelations: this.createVersionFormGroup.get('saveRelations').value,
|
versionName: this.createVersionFormGroup.get('versionName').value,
|
||||||
saveAttributes: this.createVersionFormGroup.get('saveAttributes').value,
|
config: {
|
||||||
},
|
saveRelations: this.createVersionFormGroup.get('saveRelations').value,
|
||||||
type: VersionCreateRequestType.SINGLE_ENTITY
|
saveAttributes: this.createVersionFormGroup.get('saveAttributes').value,
|
||||||
};
|
},
|
||||||
this.entitiesVersionControlService.saveEntitiesVersion(request).subscribe((result) => {
|
type: VersionCreateRequestType.SINGLE_ENTITY
|
||||||
if (!result.added && !result.modified) {
|
};
|
||||||
this.resultMessage = this.translate.instant('version-control.nothing-to-commit');
|
this.entitiesVersionControlService.saveEntitiesVersion(request).subscribe((result) => {
|
||||||
if (this.onContentUpdated) {
|
if (!result.added && !result.modified) {
|
||||||
this.onContentUpdated();
|
this.resultMessage = this.translate.instant('version-control.nothing-to-commit');
|
||||||
|
if (this.onContentUpdated) {
|
||||||
|
this.onContentUpdated();
|
||||||
|
}
|
||||||
|
} else if (this.onClose) {
|
||||||
|
this.onClose(result, request.branch);
|
||||||
}
|
}
|
||||||
} else if (this.onClose) {
|
});
|
||||||
this.onClose(result, request.branch);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
<div class="mat-padding tb-entity-table tb-absolute-fill">
|
<div class="mat-padding tb-entity-table tb-absolute-fill">
|
||||||
<div fxFlex fxLayout="column" class="mat-elevation-z1 tb-entity-table-content">
|
<div fxFlex fxLayout="column" class="tb-entity-table-content" [ngClass]="{'mat-elevation-z1': !popoverMode}">
|
||||||
<mat-toolbar class="mat-table-toolbar" [fxShow]="!textSearchMode">
|
<mat-toolbar class="mat-table-toolbar" [fxShow]="!textSearchMode">
|
||||||
<div class="mat-toolbar-tools">
|
<div class="mat-toolbar-tools">
|
||||||
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.xs="column" fxLayoutAlign.xs="center start" class="title-container">
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.xs="column" fxLayoutAlign.xs="center start" class="title-container">
|
||||||
@ -45,6 +45,11 @@
|
|||||||
<mat-icon>update</mat-icon>
|
<mat-icon>update</mat-icon>
|
||||||
{{'version-control.create-entities-version' | translate }}
|
{{'version-control.create-entities-version' | translate }}
|
||||||
</button>
|
</button>
|
||||||
|
<button mat-icon-button [disabled]="isLoading$ | async" (click)="updateData()"
|
||||||
|
matTooltip="{{ 'action.refresh' | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<mat-icon>refresh</mat-icon>
|
||||||
|
</button>
|
||||||
<button mat-icon-button
|
<button mat-icon-button
|
||||||
[disabled]="isLoading$ | async"
|
[disabled]="isLoading$ | async"
|
||||||
(click)="enterFilterMode()"
|
(click)="enterFilterMode()"
|
||||||
|
|||||||
@ -62,6 +62,12 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
|
|||||||
@Input()
|
@Input()
|
||||||
singleEntityMode = false;
|
singleEntityMode = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
popoverMode = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
onBeforeCreateVersion: () => Observable<any>;
|
||||||
|
|
||||||
displayedColumns = ['timestamp', 'id', 'name', 'author', 'actions'];
|
displayedColumns = ['timestamp', 'id', 'name', 'author', 'actions'];
|
||||||
pageLink: PageLink;
|
pageLink: PageLink;
|
||||||
textSearchMode = false;
|
textSearchMode = false;
|
||||||
@ -195,6 +201,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
|
|||||||
branch: this.branch,
|
branch: this.branch,
|
||||||
entityId: this.entityId,
|
entityId: this.entityId,
|
||||||
entityName: this.entityName,
|
entityName: this.entityName,
|
||||||
|
onBeforeCreateVersion: this.onBeforeCreateVersion,
|
||||||
onClose: (result: VersionCreationResult | null, branch: string | null) => {
|
onClose: (result: VersionCreationResult | null, branch: string | null) => {
|
||||||
createVersionPopover.hide();
|
createVersionPopover.hide();
|
||||||
if (result) {
|
if (result) {
|
||||||
@ -353,7 +360,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateData() {
|
updateData() {
|
||||||
this.pageLink.page = this.paginator.pageIndex;
|
this.pageLink.page = this.paginator.pageIndex;
|
||||||
this.pageLink.pageSize = this.paginator.pageSize;
|
this.pageLink.pageSize = this.paginator.pageSize;
|
||||||
this.pageLink.sortOrder.property = this.sort.active;
|
this.pageLink.sortOrder.property = this.sort.active;
|
||||||
|
|||||||
@ -20,6 +20,8 @@
|
|||||||
</tb-repository-settings>
|
</tb-repository-settings>
|
||||||
<ng-template #versionsTable>
|
<ng-template #versionsTable>
|
||||||
<tb-entity-versions-table [singleEntityMode]="singleEntityMode"
|
<tb-entity-versions-table [singleEntityMode]="singleEntityMode"
|
||||||
|
[popoverMode]="popoverMode"
|
||||||
|
[onBeforeCreateVersion]="onBeforeCreateVersion"
|
||||||
[active]="active"
|
[active]="active"
|
||||||
[entityId]="entityId"
|
[entityId]="entityId"
|
||||||
[entityName]="entityName"
|
[entityName]="entityName"
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard';
|
|||||||
import { RepositorySettingsComponent } from '@home/components/vc/repository-settings.component';
|
import { RepositorySettingsComponent } from '@home/components/vc/repository-settings.component';
|
||||||
import { FormGroup } from '@angular/forms';
|
import { FormGroup } from '@angular/forms';
|
||||||
import { EntityId } from '@shared/models/id/entity-id';
|
import { EntityId } from '@shared/models/id/entity-id';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-version-control',
|
selector: 'tb-version-control',
|
||||||
@ -35,6 +36,9 @@ export class VersionControlComponent implements OnInit, HasConfirmForm {
|
|||||||
@Input()
|
@Input()
|
||||||
detailsMode = false;
|
detailsMode = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
popoverMode = false;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
active = true;
|
active = true;
|
||||||
|
|
||||||
@ -50,6 +54,9 @@ export class VersionControlComponent implements OnInit, HasConfirmForm {
|
|||||||
@Input()
|
@Input()
|
||||||
entityName: string;
|
entityName: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
onBeforeCreateVersion: () => Observable<any>;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
versionRestored = new EventEmitter<void>();
|
versionRestored = new EventEmitter<void>();
|
||||||
|
|
||||||
|
|||||||
@ -164,6 +164,17 @@
|
|||||||
</tb-details-panel>
|
</tb-details-panel>
|
||||||
</mat-drawer>
|
</mat-drawer>
|
||||||
<mat-drawer-content class="tb-rulechain-graph-content">
|
<mat-drawer-content class="tb-rulechain-graph-content">
|
||||||
|
<button #versionControlButton
|
||||||
|
*ngIf="!isImport"
|
||||||
|
mat-button
|
||||||
|
color="primary"
|
||||||
|
type="button"
|
||||||
|
mat-icon-button class="mat-fab version-control-button"
|
||||||
|
(click)="toggleVersionControl($event, versionControlButton)"
|
||||||
|
matTooltip="{{'version-control.version-control' | translate}}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<mat-icon>history</mat-icon>
|
||||||
|
</button>
|
||||||
<button mat-button
|
<button mat-button
|
||||||
type="button"
|
type="button"
|
||||||
mat-icon-button class="tb-fullscreen-button"
|
mat-icon-button class="tb-fullscreen-button"
|
||||||
|
|||||||
@ -44,6 +44,21 @@
|
|||||||
margin: 0 6px;
|
margin: 0 6px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.mat-button.mat-icon-button.version-control-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 60px;
|
||||||
|
opacity: .85;
|
||||||
|
margin: 0 6px;
|
||||||
|
z-index: 2;
|
||||||
|
&.mat-fab {
|
||||||
|
.mat-button-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
section.tb-header-buttons.tb-library-open {
|
section.tb-header-buttons.tb-library-open {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|||||||
@ -17,15 +17,15 @@
|
|||||||
import {
|
import {
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef, EventEmitter,
|
||||||
HostBinding,
|
HostBinding,
|
||||||
Inject,
|
Inject,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
QueryList,
|
QueryList, Renderer2,
|
||||||
SkipSelf,
|
SkipSelf,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ViewChildren,
|
ViewChildren, ViewContainerRef,
|
||||||
ViewEncapsulation
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { PageComponent } from '@shared/components/page.component';
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
@ -63,7 +63,7 @@ import {
|
|||||||
} from '@shared/models/rule-node.models';
|
} from '@shared/models/rule-node.models';
|
||||||
import { FcRuleNodeModel, FcRuleNodeTypeModel, RuleChainMenuContextInfo } from './rulechain-page.models';
|
import { FcRuleNodeModel, FcRuleNodeTypeModel, RuleChainMenuContextInfo } from './rulechain-page.models';
|
||||||
import { RuleChainService } from '@core/http/rule-chain.service';
|
import { RuleChainService } from '@core/http/rule-chain.service';
|
||||||
import { fromEvent, NEVER, Observable, of, Subscription } from 'rxjs';
|
import { fromEvent, NEVER, Observable, of, ReplaySubject, Subscription } from 'rxjs';
|
||||||
import { debounceTime, distinctUntilChanged, mergeMap, tap } from 'rxjs/operators';
|
import { debounceTime, distinctUntilChanged, mergeMap, tap } from 'rxjs/operators';
|
||||||
import { ISearchableComponent } from '../../models/searchable-component.models';
|
import { ISearchableComponent } from '../../models/searchable-component.models';
|
||||||
import { deepClone } from '@core/utils';
|
import { deepClone } from '@core/utils';
|
||||||
@ -75,6 +75,11 @@ import { ItemBufferService, RuleNodeConnection } from '@core/services/item-buffe
|
|||||||
import { Hotkey } from 'angular2-hotkeys';
|
import { Hotkey } from 'angular2-hotkeys';
|
||||||
import { DebugEventType, EventType } from '@shared/models/event.models';
|
import { DebugEventType, EventType } from '@shared/models/event.models';
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
import { MatButton } from '@angular/material/button';
|
||||||
|
import { TbPopoverService } from '@shared/components/popover.service';
|
||||||
|
import { EntityVersionCreateComponent } from '@home/components/vc/entity-version-create.component';
|
||||||
|
import { VersionCreationResult } from '@shared/models/vc.models';
|
||||||
|
import { VersionControlComponent } from '@home/components/vc/version-control.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-rulechain-page',
|
selector: 'tb-rulechain-page',
|
||||||
@ -231,6 +236,8 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
|
|
||||||
flowchartConstants = FlowchartConstants;
|
flowchartConstants = FlowchartConstants;
|
||||||
|
|
||||||
|
updateBreadcrumbs = new EventEmitter();
|
||||||
|
|
||||||
private rxSubscription: Subscription;
|
private rxSubscription: Subscription;
|
||||||
|
|
||||||
private tooltipTimeout: Timeout;
|
private tooltipTimeout: Timeout;
|
||||||
@ -242,11 +249,13 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private itembuffer: ItemBufferService,
|
private itembuffer: ItemBufferService,
|
||||||
|
private popoverService: TbPopoverService,
|
||||||
|
private renderer: Renderer2,
|
||||||
|
private viewContainerRef: ViewContainerRef,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
public dialogService: DialogService,
|
public dialogService: DialogService,
|
||||||
public fb: FormBuilder) {
|
public fb: FormBuilder) {
|
||||||
super(store);
|
super(store);
|
||||||
|
|
||||||
this.rxSubscription = this.route.data.subscribe(
|
this.rxSubscription = this.route.data.subscribe(
|
||||||
() => {
|
() => {
|
||||||
this.reset();
|
this.reset();
|
||||||
@ -1376,7 +1385,8 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveRuleChain() {
|
saveRuleChain(): Observable<any> {
|
||||||
|
const saveResult = new ReplaySubject();
|
||||||
let saveRuleChainObservable: Observable<RuleChain>;
|
let saveRuleChainObservable: Observable<RuleChain>;
|
||||||
if (this.isImport) {
|
if (this.isImport) {
|
||||||
saveRuleChainObservable = this.ruleChainService.saveRuleChain(this.ruleChain);
|
saveRuleChainObservable = this.ruleChainService.saveRuleChain(this.ruleChain);
|
||||||
@ -1442,6 +1452,20 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
} else {
|
} else {
|
||||||
this.createRuleChainModel();
|
this.createRuleChainModel();
|
||||||
}
|
}
|
||||||
|
saveResult.next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return saveResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadRuleChain() {
|
||||||
|
this.ruleChainService.getRuleChain(this.ruleChain.id.id).subscribe((ruleChain) => {
|
||||||
|
this.ruleChain = ruleChain;
|
||||||
|
this.updateBreadcrumbs.emit();
|
||||||
|
this.ruleChainService.getRuleChainMetadata(this.ruleChain.id.id).subscribe((ruleChainMetaData) => {
|
||||||
|
this.ruleChainMetaData = ruleChainMetaData;
|
||||||
|
this.isDirtyValue = false;
|
||||||
|
this.createRuleChainModel();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1509,6 +1533,38 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
}).afterClosed();
|
}).afterClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleVersionControl($event: Event, versionControlButton: MatButton) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
const trigger = versionControlButton._elementRef.nativeElement;
|
||||||
|
if (this.popoverService.hasPopover(trigger)) {
|
||||||
|
this.popoverService.hidePopover(trigger);
|
||||||
|
} else {
|
||||||
|
const versionControlPopover = this.popoverService.displayPopover(trigger, this.renderer,
|
||||||
|
this.viewContainerRef, VersionControlComponent, 'leftTop', true, null,
|
||||||
|
{
|
||||||
|
detailsMode: true,
|
||||||
|
popoverMode: true,
|
||||||
|
active: true,
|
||||||
|
singleEntityMode: true,
|
||||||
|
externalEntityId: this.ruleChain.externalId || this.ruleChain.id,
|
||||||
|
entityId: this.ruleChain.id,
|
||||||
|
entityName: this.ruleChain.name,
|
||||||
|
onBeforeCreateVersion: () => {
|
||||||
|
if (this.isDirty) {
|
||||||
|
return this.saveRuleChain();
|
||||||
|
} else {
|
||||||
|
return of(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {width: '800px', height: '600px'}, {}, {}, true);
|
||||||
|
versionControlPopover.tbComponentRef.instance.versionRestored.subscribe(() => {
|
||||||
|
this.reloadRuleChain();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private updateNodeErrorTooltip(node: FcRuleNode) {
|
private updateNodeErrorTooltip(node: FcRuleNode) {
|
||||||
if (node.error) {
|
if (node.error) {
|
||||||
const element = $('#' + node.id);
|
const element = $('#' + node.id);
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { BehaviorSubject, Subject } from 'rxjs';
|
import { BehaviorSubject, Subject, Subscription } from 'rxjs';
|
||||||
import { BreadCrumb, BreadCrumbConfig } from './breadcrumb';
|
import { BreadCrumb, BreadCrumbConfig } from './breadcrumb';
|
||||||
import { ActivatedRoute, ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';
|
import { ActivatedRoute, ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';
|
||||||
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
||||||
@ -32,10 +32,20 @@ import { BroadcastService } from '@core/services/broadcast.service';
|
|||||||
export class BreadcrumbComponent implements OnInit, OnDestroy {
|
export class BreadcrumbComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
activeComponentValue: any;
|
activeComponentValue: any;
|
||||||
|
updateBreadcrumbsSubscription: Subscription = null;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set activeComponent(activeComponent: any) {
|
set activeComponent(activeComponent: any) {
|
||||||
|
if (this.updateBreadcrumbsSubscription) {
|
||||||
|
this.updateBreadcrumbsSubscription.unsubscribe();
|
||||||
|
this.updateBreadcrumbsSubscription = null;
|
||||||
|
}
|
||||||
this.activeComponentValue = activeComponent;
|
this.activeComponentValue = activeComponent;
|
||||||
|
if (this.activeComponentValue && this.activeComponentValue.updateBreadcrumbs) {
|
||||||
|
this.updateBreadcrumbsSubscription = this.activeComponentValue.updateBreadcrumbs.subscribe(() => {
|
||||||
|
this.breadcrumbs$.next(this.buildBreadCrumbs(this.activatedRoute.snapshot));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
breadcrumbs$: Subject<Array<BreadCrumb>> = new BehaviorSubject<Array<BreadCrumb>>(this.buildBreadCrumbs(this.activatedRoute.snapshot));
|
breadcrumbs$: Subject<Array<BreadCrumb>> = new BehaviorSubject<Array<BreadCrumb>>(this.buildBreadCrumbs(this.activatedRoute.snapshot));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user