mcgilman commented on code in PR #9548:
URL: https://github.com/apache/nifi/pull/9548#discussion_r1876724441
##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts:
##########
@@ -413,7 +630,7 @@ export class EditProcessor extends TabbedDialog {
}
override isDirty(): boolean {
- return this.editProcessorForm.dirty;
+ return this.editProcessorForm.dirty || false;
Review Comment:
Can this be removed?
##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts:
##########
@@ -253,6 +275,32 @@ export class EditProcessor extends TabbedDialog {
new FormControl({ value: this.runDurationMillis, disabled:
this.readonly }, Validators.required)
);
}
+
+ this.processRunStateUpdates(request.entity);
+ }
+
+ processRunStateUpdates(entity: any) {
Review Comment:
```suggestion
private processRunStateUpdates(entity: any) {
```
##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html:
##########
@@ -290,19 +308,79 @@ <h2 mat-dialog-title>
</mat-tab>
</mat-tab-group>
@if ({ value: (saving$ | async)! }; as saving) {
- <mat-dialog-actions align="end">
- @if (readonly) {
- <button mat-flat-button mat-dialog-close>Close</button>
- } @else {
- <button mat-button mat-dialog-close>Cancel</button>
- <button
- [disabled]="!editProcessorForm.dirty ||
editProcessorForm.invalid || saving.value"
- type="button"
- (click)="submitForm()"
- mat-flat-button>
- <span *nifiSpinner="saving.value">Apply</span>
- </button>
- }
+ <mat-dialog-actions align="start">
+ <div class="flex w-full justify-between items-center">
+ <div>
+ @if (isStoppable()) {
+ <button type="button" mat-stroked-button
[matMenuTriggerFor]="operateMenu">
+ <div class="flex items-center">
+ <i class="mr-2 success-color-default fa
fa-play"></i>Running<i
+ class="ml-2 -mt-1 fa fa-sort-desc"></i>
+ </div>
+ </button>
+ } @else if (isRunnable()) {
+ <button type="button" mat-stroked-button
[matMenuTriggerFor]="operateMenu">
+ <div class="flex items-center">
+ <i class="mr-2 error-color-variant fa
fa-stop"></i>Stopped<i
+ class="ml-2 -mt-1 fa fa-sort-desc"></i>
+ </div>
+ </button>
+ } @else {
+ <button
+ type="button"
+ mat-stroked-button
+ [disabled]="isStopping()"
+ [matMenuTriggerFor]="operateMenu">
+ <div class="flex items-center">
+ @if (isInvalid()) {
+ <i class="mr-2 fa fa-warning
caution-color"></i>
+ } @else if (isDisabled()) {
+ <i class="mr-2 icon icon-enable-false"></i>
+ } @else {
+ <i class="mr-2 fa fa-circle-o-notch
fa-spin primary-color"></i>
+ }
Review Comment:
If the user cannot operate the Processor, this will result in the showing
the spinner.
<img width="156" alt="Screenshot 2024-12-09 at 3 29 32 PM"
src="https://github.com/user-attachments/assets/138a2d55-b681-432e-81d6-62c11baf75de">
I think in this case, the button should be disabled since they don't have
permission to operate this Processor.
##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts:
##########
@@ -401,8 +460,166 @@ export class EditProcessor extends TabbedDialog {
});
}
+ hasBulletins(): boolean {
+ return this.request.entity.permissions.canRead &&
!this.nifiCommon.isEmpty(this.bulletins);
+ }
+
+ getBulletinsTipData(): BulletinsTipInput {
+ return {
+ bulletins: this.bulletins
+ };
+ }
+
+ getBulletinTooltipPosition(): ConnectedPosition {
+ return {
+ originX: 'end',
+ originY: 'bottom',
+ overlayX: 'end',
+ overlayY: 'top',
+ offsetX: -8,
+ offsetY: 8
+ };
+ }
+
+ getMostSevereBulletinLevel(): string | null {
+ // determine the most severe of the bulletins
+ const mostSevere =
this.canvasUtils.getMostSevereBulletin(this.bulletins);
+ return mostSevere ? mostSevere.bulletin.level.toLowerCase() : null;
+ }
+
+ isStoppable(): boolean {
+ if (!this.canOperate()) {
+ return false;
+ }
+
+ return this.status.aggregateSnapshot.runStatus === 'Running';
+ }
+
+ isStopping(): boolean {
+ if (!this.canOperate()) {
+ return false;
+ }
+
+ return (
+ this.status.aggregateSnapshot.runStatus === 'Stopped' &&
this.status.aggregateSnapshot.activeThreadCount > 0
+ );
+ }
+
+ isInvalid(): boolean {
+ if (!this.canOperate()) {
+ return false;
+ }
+
+ return this.status.aggregateSnapshot.runStatus === 'Invalid';
+ }
+
+ isDisabled(): boolean {
+ if (!this.canOperate()) {
+ return false;
+ }
+
+ return this.status.aggregateSnapshot.runStatus === 'Disabled';
+ }
+
+ isRunnable(): boolean {
+ if (!this.canOperate()) {
+ return false;
+ }
+
+ return (
+ !(
+ this.status.aggregateSnapshot.runStatus === 'Running' ||
+ this.status.aggregateSnapshot.activeThreadCount > 0
+ ) && this.status.aggregateSnapshot.runStatus === 'Stopped'
+ );
+ }
+
+ isDisableable(): boolean {
+ if (!this.canOperate()) {
+ return false;
+ }
+
+ return (
+ !(
+ this.status.aggregateSnapshot.runStatus === 'Running' ||
+ this.status.aggregateSnapshot.activeThreadCount > 0
+ ) &&
+ (this.status.aggregateSnapshot.runStatus === 'Stopped' ||
+ this.status.aggregateSnapshot.runStatus === 'Invalid')
+ );
+ }
+
+ isEnableable(): boolean {
+ if (!this.canOperate()) {
+ return false;
+ }
+
+ return (
+ !(
+ this.status.aggregateSnapshot.runStatus === 'Running' ||
+ this.status.aggregateSnapshot.activeThreadCount > 0
+ ) && this.status.aggregateSnapshot.runStatus === 'Disabled'
+ );
+ }
+
+ private canOperate(): boolean {
+ return this.request.entity.permissions.canWrite ||
this.request.entity.operatePermissions?.canWrite;
+ }
+
+ stop() {
+ this.stopComponentRequest.next({
+ id: this.request.entity.id,
+ uri: this.request.entity.uri,
+ type: ComponentType.Processor,
+ revision: this.client.getRevision({
+ ...this.request.entity,
+ revision: this.revision
+ }),
+ errorStrategy: 'snackbar'
+ });
+ }
+
+ start() {
+ this.startComponentRequest.next({
+ id: this.request.entity.id,
+ uri: this.request.entity.uri,
+ type: ComponentType.Processor,
+ revision: this.client.getRevision({
+ ...this.request.entity,
+ revision: this.revision
+ }),
+ errorStrategy: 'snackbar'
+ });
+ }
+
+ disable() {
+ this.disableComponentRequest.next({
+ id: this.request.entity.id,
+ uri: this.request.entity.uri,
+ type: ComponentType.Processor,
+ revision: this.client.getRevision({
+ ...this.request.entity,
+ revision: this.revision
+ }),
+ errorStrategy: 'snackbar'
+ });
+ }
+
+ enable() {
+ this.enableComponentRequest.next({
+ id: this.request.entity.id,
+ uri: this.request.entity.uri,
+ type: ComponentType.Processor,
+ revision: this.client.getRevision({
+ ...this.request.entity,
+ revision: this.revision
+ }),
+ errorStrategy: 'snackbar'
+ });
+ }
+
private getModifiedProperties(): ModifiedProperties {
- const propertyControl: AbstractControl | null =
this.editProcessorForm.get('properties');
+ const propertyControl: AbstractControl | null | undefined =
this.editProcessorForm.get('properties');
Review Comment:
Is this needed? Locally, it appears this change isn't needed and we don't
use `| undefined` elsewhere when getting controls from the form.
##########
nifi-frontend/src/main/frontend/.gitignore:
##########
@@ -45,3 +45,4 @@ Thumbs.db
.nx/cache
.nx/workspace-data
.angular
+/.tool-versions
Review Comment:
Can you move `tool-versions` entry into miscellaneous section. There are
other version front end entries that we should probably group together.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]