Skip to content

Conversation

@pvillard31
Copy link
Contributor

Summary

NIFI-13125 - Flow Version Diff View

I used #9109 as a starting point and coded something similar for NiFi 2.x. Definitely not a UI expert so my approach may not be the best one. Happy to collaborate with someone more experienced on the UI side.

This feature is particularly useful when a user sees that a versioned process group can be updated to a new version and the user would like to see what are the differences with the current version before upgrading the process group.

Access to the view is made available when listing versions for a versioned process group:

Screenshot 2025-10-28 at 23 10 04

Clicking on the diff icon for the desired version will show the diff between the current version and the selected version

Screenshot 2025-10-28 at 23 11 14

Versions can be selected via the dropdown lists:

Screenshot 2025-10-28 at 23 18 38

Filtering is also possible to filter the content of the table, and the columns can also be sorted alphabetically.

The current feature does not allow comparison across branches but that could be considered as a follow-up improvement if the community sees value into it (I'm not sure I picture a use case where it would be very useful).

Tracking

Please complete the following tracking steps prior to pull request creation.

Issue Tracking

Pull Request Tracking

  • Pull Request title starts with Apache NiFi Jira issue number, such as NIFI-00000
  • Pull Request commit message starts with Apache NiFi Jira issue number, as such NIFI-00000

Pull Request Formatting

  • Pull Request based on current revision of the main branch
  • Pull Request refers to a feature branch with one commit containing changes

Verification

Please indicate the verification steps performed prior to pull request creation.

Build

  • Build completed using ./mvnw clean install -P contrib-check
    • JDK 21
    • JDK 25

Licensing

  • New dependencies are compatible with the Apache License 2.0 according to the License Policy
  • New dependencies are documented in applicable LICENSE and NOTICE files

Documentation

  • Documentation formatting appears as expected in rendered files

@pvillard31 pvillard31 added the ui Pull requests for work relating to the user interface label Oct 28, 2025
Copy link
Contributor

@scottyaslan scottyaslan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution. I have left some comments. I am happy to review and help iterate here and continue to improve the UX for this feature.

private store = inject<Store<CanvasState>>(Store);

displayedColumns: string[] = ['current', 'version', 'created', 'comments'];
displayedColumns: string[] = ['actions', 'current', 'version', 'created', 'comments'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actions column should be displayed as the last column in the table listing.

(matSortChange)="sortData($event)"
[matSortActive]="sort.active"
[matSortDirection]="sort.direction">
<!-- Actions Column -->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actions column should be displayed as the last column in the table listing.

Comment on lines 25 to 28
.mat-column-actions {
width: 54px;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actions column is already set for all listings so we don't need this here

Suggested change
.mat-column-actions {
width: 54px;
}

Comment on lines 70 to 72
<div class="flow-diff-loading" *ngIf="isLoading">
<mat-progress-spinner diameter="36" mode="indeterminate"></mat-progress-spinner>
</div>
Copy link
Contributor

@scottyaslan scottyaslan Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The listings in nifi do not show mat-progress-spinner or any other loading UX.

Suggested change
<div class="flow-diff-loading" *ngIf="isLoading">
<mat-progress-spinner diameter="36" mode="indeterminate"></mat-progress-spinner>
</div>

Comment on lines 75 to 77
<div *ngIf="errorMessage" class="flow-diff-error" data-qa="flow-diff-error">
{{ errorMessage }}
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The listings in nifi do not show errors like this. If there is an error when requesting the diff it should be displayed in a context error banner at the top of the dialog like we do in other cases.

Suggested change
<div *ngIf="errorMessage" class="flow-diff-error" data-qa="flow-diff-error">
{{ errorMessage }}
</div>

}

ngAfterViewInit(): void {
// Sorting handled automatically when MatSort is available via the ViewChild setter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't really dug in here yet but it seems sorting is handled differently for this listing then other listings throughout nifi. I am not saying this is incorrect but it is a different pattern so at the very least it would need some testing and verification. It would be nice it we could just update this to follow the pattern used in other listings. We should not need to use a ViewChild to sort an angular material table.


<table
mat-table
*ngIf="dataSource.data.length > 0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*ngIf="dataSource.data.length > 0"

data-qa="flow-diff-message"
*ngIf="comparisonSummary.length > 0">
<div class="flow-diff-message-title">Comparing versions:</div>
<ul class="flow-diff-message-list">
Copy link
Contributor

@scottyaslan scottyaslan Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An unordered list is not the correct way to display this information. Please follow the label/value UX used throughout the application to display values. I believe we have an example in the change version dialog as well.

private store = inject<Store<CanvasState>>(Store);
private timeOffset = this.store.selectSignal(selectTimeOffset);

@ViewChild(MatSort)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can follow how the change version dialog implemented sorting instead of using a ViewChild here.

Comment on lines 284 to 297
private formatTimestamp(metadata: VersionedFlowSnapshotMetadata): string | undefined {
if (!metadata.timestamp) {
return undefined;
}

const now = new Date();
const userOffset = now.getTimezoneOffset() * 60 * 1000;
const date = new Date(metadata.timestamp + userOffset + this.getTimezoneOffset());
return this.nifiCommon.formatDateTime(date);
}

private getTimezoneOffset(): number {
return this.timeOffset() || 0;
}
Copy link
Contributor

@scottyaslan scottyaslan Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we typically format timestamps like this. Is there a reason to here? I now see that we do have two implementations of:

formatTimestamp(flowVersion: VersionedFlowSnapshotMetadata) {
        // get the current user time to properly convert the server time
        const now: Date = new Date();

        // convert the user offset to millis
        const userTimeOffset: number = now.getTimezoneOffset() * 60 * 1000;

        // create the proper date by adjusting by the offsets
        const date: Date = new Date(flowVersion.timestamp + userTimeOffset + this.timeOffset);
        return this.nifiCommon.formatDateTime(date);
    }

One in the select-flow-version.componet.ts and one in the import-from-registry.component.ts. If we really have a need for this formatting we should have a single implementation in a shared area. A new formatTimestamp Angular pipe in https://github.com/apache/nifi/tree/main/nifi-frontend/src/main/frontend/libs/shared/src/pipes would work well for this use case but I think you will find that formatting timestamps has lots or nuanced considerations. we used to have a library for this but it wasn't well maintained and was deprecated if that is any clue as to LOE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we can just leave the timestamp unformatted.

@pvillard31
Copy link
Contributor Author

Thanks for all the feedback @scottyaslan - highly appreciated! I have (hopefully) made the changes you had in mind. The only thing that is not ok is the timestamp in the dropdown lists when selecting versions. Will figure it out tomorrow. It looks so much better now, thanks for all of the review comments!

Screenshot 2025-10-30 at 22 56 03 Screenshot 2025-10-30 at 22 56 33 Screenshot 2025-10-30 at 22 57 05

@pvillard31
Copy link
Contributor Author

Addressed the timestamp issue.

Screenshot 2025-10-31 at 12 20 18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ui Pull requests for work relating to the user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants